A sintaxe do Java 7 try-with-resources (também conhecida como bloco ARM ( Gerenciamento automático de recursos )) é agradável, curta e direta ao usar apenas um AutoCloseablerecurso. No entanto, não tenho certeza de qual é o idioma correto quando preciso declarar vários recursos que dependem um do outro, por exemplo, a FileWritere a BufferedWriterque o envolvem. Obviamente, essa pergunta diz respeito a qualquer caso em que alguns AutoCloseablerecursos são agrupados, não apenas a essas duas classes específicas.
Eu vim com as três alternativas a seguir:
1)
O idioma ingênuo que eu vi é declarar apenas o wrapper de nível superior na variável gerenciada pelo ARM:
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Isso é bom e curto, mas está quebrado. Como o subjacente FileWriternão é declarado em uma variável, ele nunca será fechado diretamente no finallybloco gerado . Ele será fechado apenas pelo closemétodo de embalagem BufferedWriter. O problema é que, se uma exceção for lançada do bwconstrutor, ela closenão será chamada e, portanto, o subjacente FileWriter não será fechado .
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
}
}
Aqui, o recurso subjacente e o empacotamento são declarados nas variáveis gerenciadas pelo ARM, de modo que ambos certamente serão fechados, mas o subjacente fw.close() será chamado duas vezes : não apenas diretamente, mas também através do empacotamento bw.close().
Isso não deve ser um problema para essas duas classes específicas que ambos implementam Closeable(que é um subtipo de AutoCloseable), cujo contrato afirma que várias chamadas para closesão permitidas:
Fecha esse fluxo e libera todos os recursos do sistema associados a ele. Se o fluxo já estiver fechado, a invocação desse método não terá efeito.
No entanto, em um caso geral, posso ter recursos que implementam apenas AutoCloseable(e não Closeable), o que não garante que closepossa ser chamado várias vezes:
Observe que, diferentemente do método close de java.io.Closeable, esse método close não precisa ser idempotente. Em outras palavras, chamar esse método close mais de uma vez pode ter algum efeito colateral visível, ao contrário de Closeable.close, que é necessário para não ter efeito se chamado mais de uma vez. No entanto, os implementadores dessa interface são fortemente encorajados a tornar seus métodos próximos idempotentes.
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
}
}
Esta versão deve ser teoricamente correta, porque apenas o fwrepresenta um recurso real que precisa ser limpo. O bwpróprio não possui nenhum recurso, ele apenas delega para o fw, portanto deve ser suficiente fechar apenas o subjacente fw.
Por outro lado, a sintaxe é um pouco irregular e, também, o Eclipse emite um aviso, que acredito ser um alarme falso, mas ainda é um aviso com o qual devemos lidar:
Vazamento de recurso: 'bw' nunca é fechado
Então, qual abordagem usar? Ou eu perdi algum outro idioma que é o correto ?
public BufferedWriter(Writer out, int sz)pode jogar um IllegalArgumentException. Além disso, eu posso estender o BufferedWriter com uma classe que lançaria algo de seu construtor ou criaria qualquer invólucro personalizado que eu precisar.
BufferedWriterconstrutor pode facilmente lançar uma exceção. OutOfMemoryErroré provavelmente o mais comum, pois aloca uma boa parte da memória para o buffer (embora possa indicar que você deseja reiniciar todo o processo). / Você precisa flushseu BufferedWriterse você não fechar e quer manter o conteúdo (geralmente única o caso não exceção). FileWriterescolhe o que quer que seja a codificação de arquivo "padrão" - é melhor ser explícito.