Para qué sirve la palabra clave final en el código fuente Java

Escrito por el .
java planeta-codigo
Enlace permanente Comentarios

Java

Algunas personas y en algunos proyectos Java añaden en la declaración de cada parámetro de un método o variable local la palabra reservada final.

La palabra final tiene su utilidad pero hacerlo de forma indiscriminada y en la totalidad de cada parámetro y variable local de cada método hace más verboso el código sin proporcionar una utilidad significativa porque Java ya en ciertas circunstancias considera a muchas variables efectivamente como final, si al escribir el código se sigue la recomendación de no hacer nunca asignaciones sobre variables que son parámetros y se prefiere crear una nueva variable local en vez de modificar el valor de una existente.

¿Qué hace la palabra clave final?

La palabra clave reservada final hace que el compilador genere un error de compilación cuando a una variable final se le intenta asignar un nuevo valor. El error de compilación quizá en algún caso evita un bug ya que no debería haber intención de asignar un nuevo valor a una variable final.

La palabra clave reservada final se usa en diferentes contextos:

  • En la declaración de variables: permite declarar constantes, no se puede asignar un nuevo valor a la variable una vez inicializada.
  • En la declaración de un método: en este contexto una clase que herede un método final no puede redefinirlo en la clase hija, no se puede hacer un override.
  • En la declaración de una clase: impide extender de la clase.

Las tres formas de inicializar una variable declarada como final son:

  • En su declaración.
  • En el constructor.
  • En el contexto estático si la variable es estática.

Los constructores no pueden declararse como final ya que no se heredan.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
...

public class Bike {

   protected final int MAX_SPEED = 50;

   protected int speed = 0;

   public void setSpeed(final int speed) {
       this.speed = speed;
   }

   public final void run() {
       System.out.println("running");
   }
} 
Bike.java
1
2
3
4
5
6
7
8
9
...

public final class Honda extends Bike {
 
  public static void main(String args[]) {
      Honda honda = new Honda();
      honda.run();
  }
}
Honda.java

¿Debería añadirse la palabra clave final a cada uno de los argumentos de un método y variables locales?

En teoría, sí. En la práctica, no. Sólo es útil en métodos cuyo código es largo y complicado, y en ese caso el método debería simplificarse, o cuando el argumento tiene la posibilidad de confundirse con una variable local o miembro de la clase con la posibilidad de reasignación.

Aunque un argumento de un método se declare como final e impide asignarle un valor no se impide modificar su estado si esa variable es una referencia a un objeto como es modificar los elementos de una colección. Para evitar modificaciones en colecciones hay que hacerlas inmutables.

La palabra final en un argumento sirve para capturar un error en el que el nombre de la variable del argumento se llama igual que una propiedad de la clase en un constructor o un setter, pero usarlo de forma indiscriminada para todos los argumentos puede hacer el código aún más verboso sin proporcionar nada significativo, en los constructores y métodos setter puede ser útil como en el siguiente caso pero en el resto de métodos no es significativamente útil con el coste de legibilidad del código que genera.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
...

public class Bike { 

   ...

   public void setSpeed(final int speed) {
       speed = speed; // Compiler error: Cannot assign a value to final variable 'speed'
   }

   public void setMaxSpeed(final int speed) {
        MAX_SPEED = speed; // Compiler error: Cannot assign a value to final variable 'MAX_SPEED'
   }

   ...
} 
Bike-setter.java

Aunque una variable no se indique como final Java la considera efectivamente como final si se dan las siguientes circunstancias en el caso de que tenga inicializador:

  • No está declarada como final.
  • No aparece en la parte izquierda de una expresión de asignación (la asignación en la declaración no se considera una expresión de asignación).
  • No aparece nunca como un operando de un operador pre o post incremento o decremento.

Una variable que no tenga inicializador se considera efectivamente como final si:

  • No está declarada como final.
  • Cuando aparece como una expresión de asignación, está sin asignar.
  • No aparece nunca como un operando de un operador pre o post incremento o decremento.

Si una variable es efectivamente final añadir el modificador final no genera ningún error en tiempo de compilación. Una variable o parámetro que es declarado como final en un programa válido se convierte en efectivamente final si se elimina el modificador final.

También suele comentarse que una variable final ofrece mejor rendimiento, la diferencia de rendimiento no es significativa y si el rendimiento del programa depende de optimizarlo con palabras clave final seguramente haya muchas otras cosas a mejorar primero que el uso de palabras reservadas final. Otra justificación para el uso indiscriminado de la palabra final es en programas concurrentes con varios hilos con la intención de que los hilos no vean objetos parcialmente construidos, casos avanzados en los que quizá las primitivas de sincronización sea más adecuado.


Comparte el artículo: