O método finalize, a interface que pode ser fechada e a instrução try-with-resources (Java 7) - 1

"Olá, amigo!"

"Eu apenas decidi discutir o método finalize () com você."

"Se você se lembra, finalize() é um método especial chamado por um objeto antes que o coletor de lixo o destrua."

"O objetivo principal desse método é liberar recursos externos não-Java usados, fechando arquivos, fluxos de E/S e assim por diante."

"Infelizmente, este método não correspondeu às nossas expectativas. A máquina virtual Java pode adiar a destruição de um objeto, bem como a chamada do método finalize, o quanto quiser. Além disso, não garante que este método será chamado. Existem muitas situações em que não é chamado, tudo em nome da «otimização»."

"Eu tenho duas referências para você:"

Joshua Bloch escreveu um bom artigo sobre este método: link
Vou parafrasear um pequeno trecho:

  1. finalize() só pode ser usado em dois casos:
    1. Para verificar ou limpar recursos com log.
    2. Ao trabalhar com código nativo que não é crítico para vazamentos de recursos.
  2. finalize() torna o GC 430 vezes mais lento na limpeza de objetos
  3. finalize() pode não ser chamado
Se eu disser em uma entrevista que finalize é uma muleta prejudicial e perigosa cuja própria existência é confusa, eu estaria certo?

"Bem, isso fez o meu dia, Ellie."

"Java 7 tem uma nova instrução para substituir o método finalize . Chama-se try-with-resources . Não é realmente um substituto para finalize , mas sim uma abordagem alternativa."

"É como um try-catch, mas com recursos?"

"É quase como try-catch . O problema é que, ao contrário do método finalize (), o bloco final em uma instrução try- catch-finally é sempre executado. Os programadores também usaram essa técnica quando precisaram liberar recursos, fechar tópicos, etc.

"Aqui está um exemplo:"

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

"Independente se o bloco try foi executado corretamente ou se houve uma exceção, o bloco final sempre será chamado e é possível liberar recursos ocupados nele."

"Então, no Java 7, foi tomada a decisão de oficializar essa abordagem, assim:"

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

"Esta instrução try especial é chamada try-with-resources (semelhante a como as coleções têm uma alternativa para foreach chamado )."

"Observe que após o try existem parênteses onde variáveis ​​são declaradas e objetos são criados. Esses objetos podem ser usados ​​dentro do bloco try indicado pelas chaves. Quando o bloco try termina de ser executado, independente se terminou normalmente ou não foi uma exceção, o método close() será chamado em qualquer objeto criado dentro dos parênteses."

"Que interessante! Esta notação é muito mais compacta do que a anterior. Não tenho certeza se a entendi ainda."

"Não é tão difícil quanto você pensa."

"Então, posso especificar a classe de cada objeto entre parênteses?"

"Sim, claro, caso contrário, os parênteses seriam de pouca utilidade."

"E se eu precisar chamar outro método depois de sair do bloco try, onde coloco isso?"

"As coisas são um pouco mais sutis aqui. Java 7 apresenta a seguinte interface:"

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

"Sua classe pode implementar esta interface. E então você pode usar seus objetos dentro de uma instrução try-with-resources. Apenas tais objetos podem ser criados dentro dos parênteses de uma instrução try-with-resources para «fechamento automático»."

"Em outras palavras, preciso sobrescrever o método close e escrever código nele para 'limpar' meu objeto e não consigo especificar outro método?"

"Sim. Mas você pode especificar vários objetos - basta separá-los com um ponto e vírgula:"

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

"Isso é melhor, mas não tão legal quanto eu esperava."

"Não é tão ruim assim. Você vai se acostumar. Com o tempo."