what - Usando el modificador "final" siempre que sea aplicable en Java




what are design patterns (17)

En Java, existe la práctica de declarar todas las variables (locales o de clase), parámetro final si realmente lo son.

Aunque esto hace que el código sea mucho más detallado, esto ayuda a la lectura / captación fácil del código y también evita los errores ya que la intención está claramente marcada.

¿Qué piensas sobre esto y qué sigues?


Casi no utilizo métodos o clases finales porque me gusta permitir que las personas los anulen.

De lo contrario, solo uso finalmente si es un public/private static final type SOME_CONSTANT;


Configuré Eclipse para agregar final en todos los campos y atributos que no se modifican. Esto funciona muy bien usando las "acciones de guardado" de Eclipse, que agrega estos modificadores finales (entre otras cosas) al guardar el archivo.

Muy recomendable.

Echa un vistazo a la publicación de mi blog sobre Eclipse Save Actions.


El modificador final , especialmente para las variables, es un medio para que el compilador aplique una convención que sea generalmente sensata: asegúrese de que una variable (local o de instancia) se asigne exactamente una vez (ni más ni menos). Al asegurarse de que una variable se asigna definitivamente antes de ser utilizada, puede evitar casos comunes de una NullPointerException :

final FileInputStream in;
if(test)
  in = new FileInputStream("foo.txt");
else
  System.out.println("test failed");
in.read(); // Compiler error because variable 'in' might be unassigned

Al evitar que una variable se asigne más de una vez, desaconseja el alcance excesivo. En lugar de esto:

 String msg = null;
 for(int i = 0; i < 10; i++) {
     msg = "We are at position " + i;
     System.out.println(msg);
 }
 msg = null;

Le recomendamos usar esto:

 for(int i = 0; i < 10; i++) {
     final String msg = "We are at position " + i;
     System.out.println(msg);
 }

Algunos enlaces:


Elegir escribir el final para cada parámetro en cada método producirá mucha irritación tanto para los codificadores como para los lectores de códigos.

Una vez que la irritación va más allá del cambio razonable a Scala, donde los argumentos son finales por defecto.

O bien, siempre puede usar herramientas de diseño de código que lo harán automáticamente. Todos los IDEs los tienen implementados o como complementos.


Final cuando se usa con variables en Java proporciona un sustituto para la constante en C ++. Entonces cuando se usa final y estático para una variable, se vuelve inmutable. Al mismo tiempo, hace que los programadores migrados de C ++ sean bastante felices ;-)

Cuando se usa con variables de referencia, no le permite re-referenciar el objeto, aunque el objeto puede ser manipulado.

Cuando final se usa con un método, no permite que las subclases anulen el método.

Una vez que el uso es muy claro, debe usarse con cuidado. Principalmente depende del diseño, ya que utilizar el método final no ayudaría al polimorfismo.

Uno solo debería usarlo para las variables cuando esté absolutamente seguro de que el valor de la variable nunca se cambiará. También asegúrese de seguir la convención de codificación alentada por SUN. Por ejemplo: final int COLOR_RED = 1; (Mayúscula separada por guion bajo)

Con una variable de referencia, úsela solo cuando necesitemos una referencia inmutable a un objeto en particular.

Con respecto a la parte de legibilidad, los comentarios juegan un papel muy importante cuando se utiliza el modificador final.


Final siempre debe usarse para constantes. Incluso es útil para variables de corta duración (dentro de un único método) cuando las reglas para definir la variable son complicadas.

Por ejemplo:

final int foo;
if (a)
    foo = 1;
else if (b)
    foo = 2;
else if (c)
    foo = 3;
if (d)        // Compile error:  forgot the 'else'
    foo = 4;
else
    foo = -1;

Lo uso para constantes dentro y fuera de métodos.

A veces solo lo uso para métodos porque no sé si una subclase NO quiere anular un método dado (por las razones que sean).

En cuanto a las clases, solo para algunas clases de infraestructura, he usado la clase final.

IntelliJ IDEA le advierte si un parámetro de función está escrito dentro de una función. Por lo tanto, he dejado de usar argumentos finales para funciones. No los veo dentro de la biblioteca Java Runtime también.


Marcar la clase final también puede hacer que algunos enlaces de métodos ocurran en tiempo de compilación en lugar de en tiempo de ejecución. Considere "v2.foo ()" a continuación: el compilador sabe que B no puede tener una subclase, por lo que foo () no puede anularse, por lo que la implementación para llamar se conoce en tiempo de compilación. Si la clase B NO está marcada como final, entonces es posible que el tipo real de v2 sea alguna clase que amplíe B y anule a foo ().

class A {
    void foo() {
        //do something
    }
}
final class B extends A {
    void foo() {
    }
}
class Test {
    public void t(A v1, B v2) {
        v1.foo();
        v2.foo();
    }
}

Nunca los uso en variables locales, no tiene mucho sentido la verbosidad añadida. Incluso si no cree que la variable deba ser reasignada, eso cambiará poco la próxima persona que altere ese código que piense lo contrario, y dado que el código está siendo modificado, cualquier propósito original para hacerlo definitivo puede que ya no sea válido. Si solo es por claridad, creo que falla debido a los efectos negativos de la verbosidad.

Más o menos lo mismo se aplica a las variables miembro también, ya que proporcionan pocos beneficios, excepto en el caso de las constantes.

Tampoco influye en la inmutabilidad, ya que el mejor indicador de que algo es inmutable es que está documentado como tal y / o no tiene métodos que puedan alterar el objeto (esto, junto con hacer que la clase sea definitiva, es la única forma de garantizar que es inmutable).

Pero hey, esa es solo mi opinión :-)


Obsesionarse con:

  • Campos finales: Marcar campos como finales los fuerza a establecerse para el final de la construcción, lo que hace que la referencia de campo sea inmutable. Esto permite la publicación segura de los campos y puede evitar la necesidad de sincronización en lecturas posteriores. (Tenga en cuenta que para una referencia de objeto, solo la referencia de campo es inmutable; las cosas a las que hace referencia el objeto pueden cambiar y eso afecta la inmutabilidad).
  • Campos estáticos finales: aunque ahora utilizo las enumeraciones para muchos de los casos en los que solía usar campos finales estáticos.

Considere pero use juiciosamente:

  • Clases finales: el diseño de Framework / API es el único caso donde lo considero.
  • Métodos finales: básicamente lo mismo que las clases finales. Si está utilizando patrones de métodos de plantilla como locos y marcando cosas finales, probablemente dependa demasiado de la herencia y no lo suficiente en la delegación.

Ignore a menos que sienta anal:

  • Parámetros del método y variables locales: RAREAMENTE hago esto en gran parte porque soy flojo y me parece que desordena el código. Admitiré por completo que marcar los parámetros y las variables locales que no voy a modificar es "correcto". Desearía que fuera el predeterminado. Pero no es así y el código me resulta más difícil de entender con las finales por todas partes. Si estoy en el código de otra persona, no voy a sacarlos, pero si estoy escribiendo un nuevo código, no los incluiré. Una excepción es el caso en el que debe marcar algo final para que pueda acceder desde dentro de una clase interna anónima.

Para argumentos, creo que no son necesarios. Mostley ellos solo lastiman la readaptación. Rreasignar una variable de argumento es tan increíblemente estúpido que debería estar seguro de que pueden tratarse como constantes de todos modos.

El hecho de que Eclipse coloree el rojo final hace que sea más fácil detectar las declaraciones de variables en el código, lo que creo que mejora la lectura la mayoría de las veces.

Intento hacer cumplir la regla de que todas las variables deben ser definitivas, no existe una razón muy válida para no hacerlo. Es mucho más fácil responder al "¿qué es esta variable?" pregunta si solo tienes que encontrar la iniciación y estar seguro de que eso es todo.

De hecho, me pongo bastante nervioso con las variables no finales ahora. Es como la diferencia entre tener un cuchillo colgando de un hilo sobre tu cabeza, o simplemente tener tu cajón de cocina ...

Una variable final es simplemente una buena forma de los valores de la etiqueta.

Una variable no final está vinculada a parte de algún algoritmo propenso a errores.

Una buena característica es que cuando la opción de usar una variable fuera de la pregunta para un algoritmo la mayoría de las veces la solución es escribir un método, lo que generalmente mejora el código significativamente.


Parece que uno de los mayores argumentos en contra del uso de la palabra clave final es que "es innecesario" y "desperdicia espacio".

Si reconocemos los muchos beneficios de "final" como lo señalan muchos grandes posts aquí, aunque admito que requiere más tipeo y espacio, yo argumentaría que Java debería haber hecho variables "definitivas" por defecto, y requiere que las cosas estén marcadas " mutable "si el codificador quiere que sea.


Se recomienda encarecidamente usar el final para las constantes . Sin embargo, no lo usaría para métodos o clases (o al menos pensarlo por un tiempo), porque hace que las pruebas sean más difíciles, si no imposibles. Si definitivamente debe hacer que una clase o método sea definitivo, asegúrese de que esta clase implemente alguna interfaz, de modo que pueda tener un simulacro que implemente la misma interfaz.


Soy bastante dogmático sobre declarar todas las variables posibles como final . Esto incluye parámetros de método, variables locales y, raramente, campos de objetos de valor. Tengo tres razones principales para declarar las variables finales en todas partes:

  1. Declaración de Intención: Al declarar una variable final, afirmo que esta variable debe escribirse solo una vez. Es una sugerencia sutil para otros desarrolladores y una gran pista para el compilador.
  2. Aplicación de variables de uso único: Creo en la idea de que cada variable debe tener un solo propósito en la vida. Al asignarle a cada variable un solo propósito, se reduce el tiempo que lleva asimilar el propósito de esa variable en particular mientras se depura.
  3. Permite la optimización: sé que el compilador solía tener trucos de mejora del rendimiento que se basaban específicamente en la inmutabilidad de una referencia de variable. Me gusta pensar que algunos de estos viejos trucos de rendimiento (o nuevos) serán utilizados por el compilador.

Sin embargo, creo que las clases y los métodos finales no son tan útiles como las referencias de variables finales. La palabra clave final , cuando se usa con estas declaraciones, simplemente proporciona controles de ruta para las pruebas automatizadas y el uso de su código en formas que nunca podría haber anticipado.


Usar clases locales anónimas para los detectores de eventos y tal es un patrón común en Java. El uso más común de la palabra clave final es asegurarse de que las variables en el alcance sean accesibles para el oyente par.

Sin embargo, si se ve obligado a poner muchas declaraciones finales en su código. Esa podría ser una buena pista de que estás haciendo algo mal.

El artículo publicado arriba da este ejemplo:

public void doSomething(int i, int j) {
    final int n = i + j; // must be declared final

    Comparator comp = new Comparator() {
        public int compare(Object left, Object right) {
            return n; // return copy of a local variable
        }
    };
}

Uso final todo el tiempo para los atributos del objeto.

La palabra clave final tiene semántica de visibilidad cuando se usa en atributos de objetos. Básicamente, establecer el valor de un atributo de objeto final ocurre antes de que el constructor regrese. Esto significa que siempre que no permita que this referencia escape del constructor y use la final para todos sus atributos, su objeto está (bajo la semántica de Java 5) garantizado para ser construido adecuadamente, y dado que también es inmutable, puede ser publicado de forma segura a otros hilos.

Los objetos inmutables no se trata solo de seguridad de hilos. También hacen que sea mucho más fácil razonar acerca de las transiciones de estado en su programa, porque el espacio de lo que puede cambiar es deliberadamente y, si se usa de manera coherente, se limita por completo a solo las cosas que deberían cambiar.

A veces también hago que los métodos sean definitivos, pero no tan a menudo. Casi nunca hago clases finales. Generalmente hago esto porque tengo poca necesidad de hacerlo. Generalmente no uso mucho la herencia. Prefiero usar interfaces y composición de objetos en su lugar, esto también se presta a un diseño que a menudo resulta más fácil de probar. Cuando codifica interfaces en lugar de clases concretas, no necesita usar herencia cuando prueba, tal como está, con frameworks como jMock, mucho más fácil crear objetos simulados con interfaces que con clases concretas.

Supongo que debería hacer que la mayoría de mis clases sean finales, pero aún no me he metido en el habito.


Creo que todo tiene que ver con un buen estilo de codificación. Por supuesto, puedes escribir programas buenos y sólidos sin usar muchos modificadores final ningún lado, pero cuando lo piensas ...

Agregar final a todas las cosas que no debería cambiar simplemente reduce las posibilidades de que usted (o el próximo programador, trabajando en su código) malinterprete o haga un mal uso del proceso de pensamiento que dio como resultado su código. Al menos debería sonar algunas campanas cuando ahora quieren cambiar tu cosa previamente inmutable.

Al principio, parece incómodo ver muchas palabras clave final en tu código, pero muy pronto dejarás de notar la palabra misma y simplemente pensarás, eso-cosa-nunca-cambiará-de-este-punto -on (puedes quitármelo ;-)

Creo que es una buena práctica. No lo estoy usando todo el tiempo, pero cuando puedo y tiene sentido etiquetar algo final lo haré.





oop