La sintassi di prova con risorse di Java 7 (nota anche come blocco ARM ( Gestione automatica delle risorse )) è piacevole, breve e semplice quando si utilizza una sola AutoCloseable
risorsa. Tuttavia, io non sono sicuro di quello che è il linguaggio corretto quando ho bisogno di dichiarare più risorse che sono dipendenti l'uno dall'altro, per esempio, una FileWriter
e una BufferedWriter
che lo avvolge. Ovviamente, questa domanda riguarda qualsiasi caso in cui alcune AutoCloseable
risorse vengano spostate, non solo queste due classi specifiche.
Ho trovato le tre seguenti alternative:
1)
Il linguaggio ingenuo che ho visto è di dichiarare solo il wrapper di livello superiore nella variabile gestita da ARM:
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Questo è bello e corto, ma è rotto. Poiché il sottostante FileWriter
non è dichiarato in una variabile, non verrà mai chiuso direttamente nel finally
blocco generato . Sarà chiuso solo attraverso il close
metodo di avvolgimento BufferedWriter
. Il problema è che se un'eccezione viene generata dal bw
costruttore del, close
non verrà chiamata e quindi il sottostante FileWriter
non verrà chiuso .
2)
static void printToFile2(String text, File file) {
try (FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Qui, sia la risorsa sottostante che quella di wrapping sono dichiarate nelle variabili gestite da ARM, quindi entrambe saranno sicuramente chiuse, ma il sottostante fw.close()
sarà chiamato due volte : non solo direttamente, ma anche attraverso il wrapping bw.close()
.
Questo non dovrebbe essere un problema per queste due classi specifiche che entrambe implementano Closeable
(che è un sottotipo di AutoCloseable
), il cui contratto stabilisce che close
sono consentite più chiamate :
Chiude questo flusso e rilascia tutte le risorse di sistema ad esso associate. Se il flusso è già chiuso, invocare questo metodo non ha alcun effetto.
Tuttavia, in un caso generale, posso avere risorse che implementano solo AutoCloseable
(e non Closeable
), il che non garantisce che close
possano essere chiamate più volte:
A differenza del metodo close di java.io.Closeable, questo metodo close non deve essere idempotente. In altre parole, chiamare questo metodo vicino più di una volta può avere qualche effetto collaterale visibile, a differenza di Closeable.close, che è richiesto di non avere effetto se chiamato più di una volta. Tuttavia, gli implementatori di questa interfaccia sono fortemente incoraggiati a rendere i loro metodi vicini idempotenti.
3)
static void printToFile3(String text, File file) {
try (FileWriter fw = new FileWriter(file)) {
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Questa versione dovrebbe essere teoricamente corretta, perché solo fw
rappresenta una risorsa reale che deve essere ripulita. Lo bw
stesso non detiene alcuna risorsa, delega solo a fw
, quindi dovrebbe essere sufficiente chiudere solo il sottostante fw
.
D'altra parte, la sintassi è un po 'irregolare e, inoltre, Eclipse emette un avviso, che credo sia un falso allarme, ma è comunque un avvertimento che si deve affrontare:
Perdita di risorse: 'bw' non viene mai chiuso
Quindi, quale approccio scegliere? O ho perso qualche altro idioma che è quello corretto ?
public BufferedWriter(Writer out, int sz)
può lanciare un IllegalArgumentException
. Inoltre, posso estendere BufferedWriter con una classe che potrebbe lanciare qualcosa dal suo costruttore o creare un wrapper personalizzato di cui ho bisogno.
BufferedWriter
costruttore può facilmente generare un'eccezione. OutOfMemoryError
è probabilmente il più comune in quanto alloca una buona porzione di memoria per il buffer (anche se può indicare che si desidera riavviare l'intero processo). / È necessario il flush
tuo BufferedWriter
se non si chiude e si desidera conservare i contenuti (in genere solo il caso di non eccezione). FileWriter
raccoglie qualunque sia la codifica di file "predefinita" - è meglio essere espliciti.