Java try-with-resources
Feche recursos AutoCloseable automaticamente em Java com a instrução try-with-resources.
A instrução try-with-resources é a solução do Java para o padrão "abrir, usar, sempre fechar". Você declara um recurso no início do try, e a JVM garante que ele será fechado quando o bloco terminar — seja com retorno normal, com uma exceção lançada ou com qualquer outro fluxo de controle. O trabalhoso padrão com finally se reduz a uma única declaração.
Este capítulo abrange a sintaxe, o que se qualifica como recurso, como múltiplos recursos são fechados, o mecanismo de exceções suprimidas que torna o recurso confiável e quando não utilizá-lo.
A estrutura
try (FileReader reader = new FileReader(path)) {
// use reader
}É só isso. Sem finally, sem close() explícito. Quando o try termina, a JVM chama reader.close() automaticamente. As cláusulas catch e finally que você adicionar continuam funcionando — elas são executadas após o fechamento do recurso.
try (FileReader reader = new FileReader(path)) {
// use reader
} catch (IOException e) {
// handle — at this point the reader is already closed
}O que pode ser um recurso
Um recurso precisa implementar AutoCloseable (ou sua subinterface mais antiga Closeable). Essa interface declara um único método:
public interface AutoCloseable {
void close() throws Exception;
}A maioria dos tipos que você usaria já a implementa: InputStream, OutputStream, Reader, Writer, Connection, Statement, ResultSet, Scanner, wrappers de Lock e muitos clientes de terceiros. Se você estiver escrevendo uma classe que possui um recurso, implemente AutoCloseable por conta própria.
Múltiplos recursos
Separe as declarações com ponto e vírgula. Os recursos são fechados na ordem inversa da declaração, portanto o último aberto é o primeiro fechado:
try (
FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst)
) {
in.transferTo(out);
}
// closes `out` first, then `in`A ordem inversa importa porque o segundo recurso frequentemente depende do primeiro. Fechar o dependente primeiro mantém a base intacta por mais um momento, o que é a ordem mais segura.
Reutilizando recursos existentes (Java 9+)
Se você já tem uma variável que contém um AutoCloseable, não precisa declarar uma nova — passe-a pelo nome:
BufferedReader reader = openSomewhere();
try (reader) {
// use it
}A variável precisa ser final ou efetivamente final (você não pode reatribuí-la). Essa forma é útil quando um recurso é construído em outro lugar — ao custo de tornar o fechamento menos visível. Use-a quando a variável existente estiver bem à mão; caso contrário, prefira a declaração inline.
Exceções suprimidas
Aqui está a parte sutil. O que acontece se o corpo do try lançar uma exceção e a chamada a close() também lançar? Antes do Java 7, a exceção de fechamento do finally substituiria a original — e você perderia a causa real.
O try-with-resources resolve isso. A exceção original é a que é lançada ao chamador; quaisquer exceções ocorridas no fechamento são anexadas a ela como exceções suprimidas, recuperáveis com Throwable.getSuppressed():
try (Resource r = new Resource()) {
r.use(); // throws A
} // close() throws B
// caller sees A
// A.getSuppressed() returns [B]O printStackTrace() padrão também imprime as exceções suprimidas (linhas Suppressed: ... abaixo da principal). Você quase nunca precisa lidar com isso manualmente — a linguagem preserva a cadeia por você.
Uma forma típica real
Um padrão comum, reunindo tudo:
public List<String> readAllLines(Path p) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(p)) {
return reader.lines().toList();
}
}Pontos a observar: sem fechamento explícito, sem finally, o corpo pode retornar diretamente com return, e o chamador ainda recebe uma IOException limpa se algo falhar.
Quando try-with-resources é a ferramenta errada
É a ferramenta certa sempre que você possui o ciclo de vida completo do recurso em um único bloco. É errada quando:
- O recurso vive mais que o bloco — por exemplo, uma conexão em cache entre chamadas. Fechá-la ao final do método quebraria o próximo usuário.
- Você não possui o recurso — um chamador o passou para você. Ele mesmo o fechará.
Nesses casos, deixe o fechamento para o dono. Se você não conseguir identificar quem é o dono, isso é um indício de problema de design — descubra antes de escrever o código.
Um exemplo prático
Um programa curto que copia uma string para um pipe em memória e a lê de volta por meio de um leitor com buffer. Ambos os streams são AutoCloseable; ambos são fechados automaticamente; adicionamos um pequeno recurso personalizado para que você possa ver a ordem de fechamento na saída.
Na saída você pode ver que a ordem de declaração é a, b, src, buf, mas a ordem de fechamento é inversa: buf, src, b, a. Essa é a garantia da linguagem — o primeiro aberto é o último fechado.
O que vem a seguir
Até agora estávamos apenas capturando exceções lançadas pelo Java. O código real também precisa lançar as suas próprias — para argumentos inválidos, invariantes quebradas ou falhas de domínio. Continue em Java throw and throws.