El método de finalización, la interfaz que se puede cerrar y la declaración de prueba con recursos (Java 7) - 1

"¡Hola, amigo!"

"Decidí hablar contigo sobre el método finalizar ()".

"Si recuerdas, finalize() es un método especial que es llamado por un objeto antes de que el recolector de basura lo destruya".

"El propósito principal de este método es liberar recursos externos que no sean de Java al cerrar archivos, flujos de E/S, etc.".

"Desafortunadamente, este método no está a la altura de nuestras expectativas. La máquina virtual de Java puede posponer la destrucción de un objeto, así como llamar al método finalize, todo el tiempo que quiera. Además, no garantiza que este método será llamado en absoluto. Hay un montón de situaciones en las que no se llama, todo en nombre de la «optimización»."

"Tengo dos referencias para usted:"

Joshua Bloch ha escrito un buen artículo sobre este método: link
Voy a parafrasear un breve extracto:

  1. finalize() solo se puede usar en dos casos:
    1. Para verificar o limpiar recursos con registro.
    2. Cuando se trabaja con código nativo que no es crítico para las fugas de recursos.
  2. finalize() hace que el GC sea 430 veces más lento para limpiar objetos
  3. finalize() podría no ser llamado
Si digo en una entrevista que finalizar es una muleta dañina y peligrosa cuya mera existencia es confusa, ¿estaría en lo cierto?

"Bueno, eso me alegró el día, Ellie".

"Java 7 tiene una nueva declaración para reemplazar el método finalize . Se llama try-with-resources . No es realmente un reemplazo para finalizar , sino que es un enfoque alternativo".

"¿Es como intentar atrapar, pero con recursos?"

"Es casi como try-catch . La cosa es que, a diferencia del método finalize (), el bloque finalmente en una instrucción try- catch-finally siempre se ejecuta. Los programadores también han usado esta técnica cuando han necesitado liberar recursos, cerrar hilos, etc.

"Aquí hay un ejemplo:"

InputStream is = null;
try
{
 is = new FileInputStream("c:/file.txt");
 is.read(…);
}
finally
{
 if (is != null)
 is.close();
}

"Independientemente de si el bloque de prueba se ejecutó correctamente o hubo una excepción, el bloque finalmente siempre se llamará y es posible liberar los recursos ocupados allí".

"Entonces, en Java 7, se tomó la decisión de hacer oficial este enfoque, así:"

try(InputStream is = new FileInputStream("c:/file.txt"))
{
 is.read(…);
}

"Esta declaración de prueba especial se llama prueba con recursos (similar a cómo las colecciones tienen una alternativa para llamada foreach )".

"Observe que después del intento hay paréntesis donde se declaran las variables y se crean los objetos. Estos objetos se pueden usar dentro del bloque de prueba indicado por los corchetes. Cuando el bloque de prueba termina de ejecutarse, independientemente de si terminó normalmente o no fue una excepción, se llamará al método close() en cualquier objeto creado dentro de los paréntesis".

"¡Qué interesante! Esta notación es mucho más compacta que la anterior. No estoy seguro de entenderla todavía".

"No es tan difícil como crees".

"Entonces, ¿puedo especificar la clase de cada objeto entre paréntesis?"

"Sí, por supuesto, de lo contrario los paréntesis serían de poca utilidad".

"Y si necesito llamar a otro método después de salir del bloque de prueba, ¿dónde lo pongo?"

"Las cosas son un poco más sutiles aquí. Java 7 presenta la siguiente interfaz:"

public interface AutoCloseable
{
 void close() throws Exception;
}

"Su clase puede implementar esta interfaz. Y luego puede usar sus objetos dentro de una declaración de prueba con recursos. Solo tales objetos pueden crearse dentro de los paréntesis de una declaración de prueba con recursos para el «cierre automático»."

"En otras palabras, necesito anular el método de cierre y escribir código en él para "limpiar" mi objeto, ¿y no puedo especificar otro método?"

"Sí. Pero puede especificar varios objetos, simplemente sepárelos con un punto y coma:"

try(
InputStream is = new FileInputStream("c:/file.txt");
OutputStream os = new FileOutputStream("c:/output.txt")
)
{
 is.read(…);
 os.write(…);
}

"Eso es mejor, pero no tan genial como esperaba".

"No es tan malo. Te acostumbrarás. Con el tiempo".