Idioma corretto per la gestione di più risorse concatenate nel blocco try-with-resources?

La syntax try-with-resources di Java 7 (nota anche come blocco ARM ( Automatic Resource Management )) è semplice, breve e diretta quando si utilizza una sola risorsa AutoCloseable . Tuttavia, non sono sicuro di quale sia l’idioma corretto quando devo dichiarare più risorse che dipendono l’una dall’altra, ad esempio un FileWriter e un BufferedWriter che lo avvolge. Ovviamente, questa domanda riguarda ogni caso in cui alcune risorse AutoCloseable sono incapsulate, non solo queste due classi specifiche.

Ho trovato le tre alternative seguenti:

1)

L’idioma ingenuo che ho visto è quello di dichiarare solo il wrapper di primo livello 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 breve, ma è rotto. Poiché il FileWriter sottostante non è dichiarato in una variabile, non verrà mai chiuso direttamente nel blocco finally generato. Sarà chiuso solo attraverso il metodo close del wrapping BufferedWriter . Il problema è che se un’eccezione viene lanciata dal costruttore di bw , la sua close non verrà chiamata e quindi il FileWriter sottostante 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 wrapping sono dichiarate nelle variabili gestite da ARM, quindi entrambe saranno certamente chiuse, ma il sottostante fw.close() verrà 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 entrambi implementano Closeable (che è un sottotipo di AutoCloseable ), il cui contratto stabilisce che sono consentite più chiamate da close :

    Chiude questo stream e rilascia tutte le risorse di sistema ad esso associate. Se lo stream è già chiuso, il richiamo di questo metodo non ha alcun effetto.

    Tuttavia, in un caso generale, posso disporre di risorse che implementano solo AutoCloseable (e non Closeable ), che non garantisce che la close possa essere richiamata più volte:

    Nota che a differenza del metodo close di java.io.Closeable, questo metodo close non è richiesto per 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 non richiede alcun effetto se viene 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 la fw rappresenta una vera risorsa che deve essere ripulita. Il bw non contiene di per sé alcuna risorsa, si limita a debind al fw , quindi dovrebbe essere sufficiente chiudere solo il fw sottostante.

    D’altra parte, la syntax è un po ‘irregolare e, inoltre, Eclipse emette un avviso, che credo sia un falso allarme, ma è pur sempre un avvertimento che bisogna affrontare:

    Perdita di risorse: “bw” non viene mai chiuso


    Quindi, quale approccio scegliere? O ho perso qualche altro idioma che è quello giusto ?