W3docs

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.

java— editable, runs on the server

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.

Prática

Prática
Um bloco `try-with-resources` abre dois recursos `AutoCloseable`. O corpo lança uma `IOException`, e o `close()` do segundo recurso também lança uma `IOException`. O que o chamador vê?
Um bloco `try-with-resources` abre dois recursos `AutoCloseable`. O corpo lança uma `IOException`, e o `close()` do segundo recurso também lança uma `IOException`. O que o chamador vê?
Was this page helpful?