Il metodo finalize, l'interfaccia chiudibile e l'istruzione try-with-resources (Java 7) - 1

"Ciao, Amico!"

"Ho appena deciso di discutere con te il metodo finalize ()."

"Se ricordi, finalize() è un metodo speciale che viene chiamato da un oggetto prima che il Garbage Collector lo distrugga."

"Lo scopo principale di questo metodo è liberare risorse esterne non Java utilizzate chiudendo file, flussi di I/O e così via."

"Sfortunatamente, questo metodo non è all'altezza delle nostre aspettative. La macchina virtuale Java può posticipare la distruzione di un oggetto, così come chiamare il metodo finalize, finché lo desidera. Inoltre, non garantisce che questo metodo sarà chiamato affatto. Ci sono un sacco di situazioni in cui non viene chiamato, tutto in nome dell'«ottimizzazione»."

"Ho due referenze per te:"

Joshua Bloch ha scritto un buon articolo su questo metodo: link
parafraserò un breve estratto:

  1. finalize() può essere utilizzato solo in due casi:
    1. Per verificare o ripulire le risorse con la registrazione.
    2. Quando si lavora con codice nativo che non è critico per le perdite di risorse.
  2. finalize() rende il GC 430 volte più lento nella pulizia degli oggetti
  3. finalize() potrebbe non essere chiamato
Se in un'intervista dico che finalizzare è una stampella dannosa e pericolosa la cui stessa esistenza crea confusione, avrei ragione?

"Beh, questo mi ha migliorato la giornata, Ellie."

"Java 7 ha una nuova istruzione per sostituire il finalize metodo. Si chiama try-with-resources . Non è in realtà un sostituto di finalize , piuttosto è un approccio alternativo."

"È come tentare la cattura, ma con le risorse?"

"È quasi come try-catch . Il fatto è che, a differenza del metodo finalize (), il blocco finally in un'istruzione try- catch-finally viene sempre eseguito. I programmatori hanno utilizzato questa tecnica anche quando avevano bisogno di liberare risorse, chiudi thread, ecc.

"Ecco un esempio:"

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

"Indipendentemente dal fatto che il blocco try sia stato eseguito correttamente o che si sia verificata un'eccezione, il blocco finally verrà sempre chiamato ed è possibile rilasciare le risorse occupate lì."

"Quindi, in Java 7, è stata presa la decisione di rendere ufficiale questo approccio, in questo modo:"

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

"Questa istruzione try speciale è chiamata try-with-resources (simile a come le raccolte hanno un'alternativa per chiamata foreach )."

"Notare che dopo il try ci sono parentesi in cui vengono dichiarate le variabili e vengono creati gli oggetti. Questi oggetti possono essere usati all'interno del blocco try indicato dalle parentesi graffe. Quando il blocco try ha finito di essere eseguito, indipendentemente dal fatto che sia terminato normalmente o lì era un'eccezione, il metodo close() verrà chiamato su tutti gli oggetti creati all'interno delle parentesi."

"Che interessante! Questa notazione è molto più compatta della precedente. Non sono sicuro di averla ancora capita."

"Non è così difficile come pensi."

"Allora, posso specificare la classe di ciascun oggetto tra parentesi?"

"Sì, certo, altrimenti le parentesi servirebbero a poco."

"E se devo chiamare un altro metodo dopo essere uscito dal blocco try, dove lo metto?"

"Le cose sono un po' più sottili qui. Java 7 introduce la seguente interfaccia:"

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

"La tua classe può implementare questa interfaccia. E poi puoi usare i suoi oggetti all'interno di un'istruzione try-with-resources. Solo tali oggetti possono essere creati all'interno delle parentesi di un'istruzione try-with-resources per la «chiusura automatica»."

"In altre parole, devo sovrascrivere il metodo close e scriverci del codice per «ripulire» il mio oggetto, e non posso specificare un altro metodo?"

"Sì. Ma puoi specificare diversi oggetti, basta separarli con un punto e virgola:"

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

"Va meglio, ma non così bello come speravo."

"Non è poi così male. Ti ci abituerai. Con il tempo."