¿Por qué la palabra clave 'final' se usa tan poco en la industria? [cerrado]

14

Desde que descubrí los poderes de la finalpalabra clave en Java hace unos años, me ayudó a hacer que mis códigos fueran mucho más legibles, ya que las personas pueden ver fácilmente cuáles son las variables de solo lectura. También puede proporcionar un pequeño impulso al JIT, y aunque es muy limitado, no puede dañar, especialmente cuando se dirige a dispositivos integrados como plataformas de Android.

Pero más que todo, contribuye a hacer un diseño más robusto a los cambios, y guía a otros confirmadores cuando necesitan modificar la base del código.

Sin embargo, mientras exploraba parte del código fuente de JDK, nunca me topé con esta palabra clave, ya sea para clases, métodos o variables. Lo mismo se aplica a varios sistemas que tuve que revisar.

¿Hay una razón? ¿Es un paradigma de diseño común dejar que todo sea mutable desde adentro?

Aurelien Ribon
fuente
en micro optimizaciones, el establecimiento de finalcampos tiene la misma semántica que escribir un volatilecampo y, a continuación, leerlos más tarde tiene que tener la semántica de lectura volátiles, esto no siempre es lo que quieren
trinquete monstruo
55
@ratchet: Creo que se trata más de hacer que sus clases sean inmutables, como en la programación funcional.
Jonas
@Kwebble: Quizás lo más importante es que las instancias individuales de String son inmutables.
MatrixFrog

Respuestas:

9

Sospecho que la razón por la que no lo ve es porque el JDK está diseñado para extenderse (es la base sobre la que se basan todos sus programas). No sería raro que el código de la aplicación lo utilice. Tampoco esperaría ver mucho en el código de la biblioteca (ya que las bibliotecas a menudo también están diseñadas para la extensión).

Intenta echar un vistazo a algunos buenos proyectos de código abierto y creo que encontrarás más.

En contraste con lo que está viendo en Java, en el mundo .NET, he escuchado el argumento muchas veces de que las clases deberían ser sealed(similares a las aplicadas a una clase) de forma predeterminada, y que el desarrollador debería deseleccionar explícitamente eso.

Steven Evers
fuente
2
Incluso me refería a muchos miembros privados o protegidos de algunas clases JDK que obviamente son "generar una vez, nunca anular" las variables de objeto. Particularmente en el paquete de columpios. Esos son candidatos perfectos para 'final', ya que su reemplazo con un puntero nulo conduciría a errores al usar los componentes.
Aurelien Ribon
1
@ Aurélien: Si te hace sentir mejor, muchas de las clases en .NET Framework están selladas, para consternación de algunos usuarios que desean ampliar las clases de framework con su propia funcionalidad. Sin embargo, esta limitación puede mitigarse un poco mediante el uso de métodos de extensión.
Robert Harvey
1
Creo que esto se trata más de la inmutabilidad que de evitar la extensión. En otras palabras, el uso de finalen campos y no en métodos. Las clases inmutables también pueden diseñarse para extenderse.
Jonas
15

El problema con el uso finalpara transmitir que algo es de solo lectura es que realmente solo funciona para tipos primitivos como int, charetc. Todos los objetos en Java en realidad se refieren al uso de un (tipo de) puntero. Como resultado, cuando usa la finalpalabra clave en un objeto, solo está diciendo que la referencia es de solo lectura, el objeto en sí sigue siendo mutable.

Podría haberse usado más si realmente hiciera que el objeto fuera de solo lectura. En C ++ eso es exactamente lo que consthace y, como resultado, es una palabra clave mucho más útil y muy utilizada.

Un lugar donde uso mucho la finalpalabra clave es con parámetros para evitar cualquier confusión creada por cosas como esta:

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

En este ejemplo, parece obvio por qué esto no funciona, pero si someMethod(FancyObject)es grande y puede producirse una confusión complicada. ¿Por qué no evitarlo?

También es parte de los estándares de codificación de Sun (u Oracle ahora supongo).

Gyan alias Gary Buyn
fuente
1
Si se ha utilizado más finalen las clases de API de Java, la mayoría de los objetos han sido inmutables como en muchas bibliotecas de Scala. Luego, hacer campos de objetos finalhace que la clase sea inmutable en muchos casos. Este diseño ya se usa en BigDecimaly String.
Jonas
@Jonas Leí la pregunta sobre el punto 4 en la respuesta de schmmd ya que decía "ya que la gente puede ver fácilmente cuáles son las variables de solo lectura" y respondió en consecuencia. Tal vez debería haber incluido esa suposición en la respuesta.
Gyan alias Gary Buyn
Tenga en cuenta que hay momentos en los que desea reasignar el parámetro. Como ejemplo se está recortando un parámetro de cadena.
Steve Kuo
@ Steve Normalmente creo una nueva variable para asignar en esa situación.
Gyan alias Gary Buyn
1
@Gary, al menos para mí, es muy raro que los errores / confusión sean causados ​​por la reasignación de un parámetro. Prefiero tener un código libre de desorden y aceptar la posibilidad remota de reasignar un parámetro que causa un error. Solo tenga cuidado al escribir / modificar código.
Steve Kuo
4

Estoy de acuerdo en que la finalpalabra clave mejora la legibilidad. Hace que sea mucho más fácil de entender cuando un objeto es inmutable. Sin embargo, en Java es extremadamente detallado, particularmente (en mi opinión) cuando se usa en parámetros. Esto no quiere decir que las personas no deberían usarlo porque es detallado, sino que no lo usan porque es detallado.

Algún otro idioma, como scala, hace que sea mucho más fácil hacer declaraciones finales ( val ). En estos idiomas, las declaraciones finales pueden ser más comunes que las variables.

Tenga en cuenta que hay muchos usos diferentes de la palabra clave final. Su publicación cubre principalmente los artículos 2 y 3.

  1. Clases finales (JLS 8.1.1.2)
  2. Campos finales (JLS 8.3.1.2)
  3. Métodos finales (JLS 8.4.3.3)
  4. Variables finales (JLS 4.12.4)
schmmd
fuente
2

Bueno, para empezar, las convenciones oficiales de código Java no favorecen ni prohíben el uso particular de final. Es decir, los desarrolladores de JDK son libres de elegir la forma que prefieran.

No puedo leer su mente, pero para mí, la preferencia sobre si usarla finalo no ha sido una cuestión de enfoque. Una cuestión de si tengo tiempo suficiente para concentrarme completamente en el código o no .

  • Digamos que en uno de mis proyectos podríamos permitirnos gastar un promedio de un día en como 100 líneas de código. En este proyecto, tenía una percepción clara de finalbasura que solo oscurece las cosas que ya se expresan con suficiente claridad en el código. Parece que los desarrolladores de JDK también entran en esa categoría.
     
    Por otro lado, fue totalmente opuesto en otro proyecto, donde pasamos una hora promedio en 100 líneas de código. Allí, me encontré disparando finalcomo un arma mashine en mi propio código y en el de los demás, simplemente porque era la forma más rápida de detectar una intención del tipo que lo escribió antes que yo y, de manera similar, la forma más rápida de comunicar mi propia intención. El tipo que trabajará en mi código más tarde.

También puede proporcionar un pequeño impulso al JIT, y aunque es muy limitado, no puede dañar

El razonamiento como el anterior es resbaladizo. La optimización prematura puede dañar; Donald Knuth llega a llamarlo "la raíz de todo mal" . No dejes que te atrape. Escribe código tonto .

mosquito
fuente
2

Recientemente descubrí la alegría de la función "Guardar acciones" en Eclipse IDE. Puedo forzarlo a formatear mi código, insertar @Overrideanotaciones faltantes y hacer algunas cosas ingeniosas como eliminar paréntesis innecesarios en expresiones o poner finalpalabras clave en todas partes automáticamente cada vez que presiono ctrl + S. ¡Activé algunos de esos factores desencadenantes y, vaya, ayuda mucho!

Resultó que muchos de esos desencadenantes actúan como una verificación rápida de mi código.

  • Tenía la intención de anular un método pero la anotación no apareció cuando presioné ctrl + s? - ¡Quizás arruiné tipos de parámetros en alguna parte!
  • ¿Se eliminaron algunos paréntesis del código al guardar? - tal vez esa expresión lógica es demasiado difícil para que un programador pueda moverse rápidamente. De lo contrario, ¿por qué agregaría esos paréntesis en primer lugar?
  • Ese parámetro o variable local no lo es final. ¿ Tiene que cambiar su valor?

Resultó que cuantas menos variables cambien, menos problemas tendré en el momento de la depuración. ¿Cuántas veces seguías el valor de alguna variable solo para descubrir que de alguna manera cambia de 5 a 7? "¡¿Cómo demonios podría ser ?!" te preguntas y pasas las próximas dos horas entrando y saliendo de innumerables métodos para descubrir que has cometido un error en tu lógica. Y para solucionarlo, debe agregar una bandera más, un par de condiciones y cambiar cuidadosamente algunos valores aquí y allá.

¡Oh, odio la depuración! ¡Cada vez que ejecuto el depurador siento que se me acaba el tiempo y necesito desesperadamente ese tiempo para hacer realidad al menos algunos de los sueños de mi infancia! ¡Al diablo con la depuración! finals significa que no habrá más cambios de valor misteriosos. Más finals => partes menos endebles en mi código => menos errores => ¡más tiempo para hacer cosas buenas!

En cuanto a las finalclases y los métodos, realmente no me importa. Amo el polimorfismo. Polimorfismo significa reutilización significa menos código significa menos errores. JVM hace un trabajo bastante bueno con la desvirtualización y la línea de métodos de todos modos, así que no veo un valor en matar las posibilidades de reutilización de código para obtener beneficios de rendimiento poco sólidos.


Ver todas esas finals en el código es algo molesto al principio y lleva tiempo acostumbrarse también. Algunos de mis compañeros de equipo todavía se sorprenden al ver tantas finalpalabras clave. Ojalá hubiera una configuración en el IDE para colorear sintaxis especial. Me encantaría cambiarlo a un tono gris (como anotaciones) para que no distraigan demasiado al leer el código. Eclipse actualmente tiene un color separado para returny todas las demás palabras clave, pero no para final.

Andrew Андрей Листочкин
fuente
1
Quizás podría considerar buscar lenguajes funcionales como OCaml o F #. Estos lenguajes tienden a requerir mucho menos depuración, una de las razones es que todo es de solo lectura de forma predeterminada. En pocas palabras, una vez asignada, una variable en un lenguaje funcional no cambia.
Abel
1
Sí, lo sé y de hecho escribo un código de ML de vez en cuando, de ahí es de donde saqué mi inspiración :) No se trata del lenguaje que usas, sino de los principios y técnicas que aplicas. Uno puede volverse imperativo con Haskell y la donotación :) Claro, Java no es el mejor lenguaje para escribir en un estilo funcional, pero al menos le permite escribir código robusto, y eso es lo que realmente me importa.
Andrew Андрей Листочкин