En mi experiencia, hay una y solo una razón para anular Object.finalize()
, pero es una muy buena razón :
Para colocar el código de registro de errores en el finalize()
que le notifica si alguna vez olvida invocar close()
.
El análisis estático solo puede detectar omisiones en escenarios de uso triviales, y las advertencias del compilador mencionadas en otra respuesta tienen una visión tan simplista de las cosas que realmente tiene que deshabilitarlas para hacer algo no trivial. (Tengo muchas más advertencias habilitadas que cualquier otro programador que conozca o haya escuchado, pero no tengo habilitadas las advertencias estúpidas).
La finalización puede parecer un buen mecanismo para asegurarse de que los recursos no se disuelvan, pero la mayoría de las personas lo ven de una manera completamente incorrecta: piensan que es un mecanismo alternativo alternativo, una salvaguardia de "segunda oportunidad" que salvará automáticamente día al deshacerse de los recursos que olvidaron. Esto está muy mal . Debe haber una sola forma de hacer cualquier cosa: o siempre cierras todo o la finalización siempre cierra todo. Pero como la finalización no es confiable, la finalización no puede serlo.
Por lo tanto, existe este esquema que llamo Eliminación obligatoria , y estipula que el programador es responsable de cerrar siempre explícitamente todo lo que implementa Closeable
o AutoCloseable
. (La declaración de prueba con recursos todavía cuenta como cierre explícito). Por supuesto, el programador puede olvidar, así que ahí es donde entra en juego la finalización, pero no como un hada mágica que mágicamente hará las cosas bien al final: si la finalización descubre que close()
no fue invocado, nointente invocarlo, precisamente porque (con certeza matemática) habrá hordas de programadores n00b que dependerán de él para hacer el trabajo que eran demasiado vagos o demasiado distraídos para hacer. Entonces, con la disposición obligatoria, cuando la finalización descubre que close()
no se invocó, registra un mensaje de error rojo brillante, diciéndole al programador con mayúsculas grandes y gruesas que arreglen sus cosas.
Como beneficio adicional, se rumorea que "la JVM ignorará un método trivial finalize () (p. Ej., Uno que simplemente regresa sin hacer nada, como el definido en la clase Object)", por lo que con la eliminación obligatoria puede evitar toda finalización sobrecarga en todo su sistema ( vea la respuesta de alip para obtener información sobre cuán terrible es esta sobrecarga) codificando su finalize()
método de esta manera:
@Override
protected void finalize() throws Throwable
{
if( Global.DEBUG && !closed )
{
Log.Error( "FORGOT TO CLOSE THIS!" );
}
//super.finalize(); see alip's comment on why this should not be invoked.
}
La idea detrás de esto es que Global.DEBUG
es una static final
variable cuyo valor se conoce en el momento de la compilación, por lo que si es false
así, el compilador no emitirá ningún código para toda la if
declaración, lo que lo convertirá en un finalizador trivial (vacío), que a su vez significa que su clase será tratada como si no tuviera un finalizador. (En C # esto se haría con un buen #if DEBUG
bloque, pero qué podemos hacer, esto es Java, donde pagamos aparente simplicidad en el código con una sobrecarga adicional en el cerebro).
Más información sobre la eliminación obligatoria, con una discusión adicional sobre la eliminación de recursos en dot Net, aquí: michael.gr: eliminación obligatoria frente a la abominación de "eliminación y eliminación"
finalize()
está un poco desordenada. Si alguna vez lo implementa, asegúrese de que sea seguro para subprocesos con respecto a todos los demás métodos en el mismo objeto.