Fechar recursos automaticamente (Java 7)

O Java 7 possui uma funcionalidade interessante para diminuir um pouco o código e evitar problemas em locais onde recursos precisam ser fechados (conexão com banco, manipulação de arquivos, sockets, streams em geral, ...). Essa funcionalidade é conhecida como try-with-resources.

Antes do Java 7, para ler um arquivo tínhamos que fazer o seguinte:

		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader("teste.txt"));
			String txt = null;
			while ((txt = br.readLine()) != null) {
				System.out.println(txt);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(br!=null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

Com o uso do try-with-resources, podemos eliminar o "fechamento" do arquivo:

		try (BufferedReader br = new BufferedReader(new FileReader("teste.txt"))) {
			String txt = null;
			while ((txt = br.readLine()) != null) {
				System.out.println(txt);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

Dentro dos parênteses do try devemos colocar a declaração de uma ou mais variáveis de classes que implementam a interface AutoCloseable. Para garantir que isso funciona, vamos criar uma classe que implementa a interface AutoCloseable:

public class AutoFechavel implements AutoCloseable {
	@Override
	public void close() throws Exception {
		System.out.println("Fechou!!!");
	}
}

Agora vamos colocá-la dentro do novo try:

package br.com.thiagovespa.sample.java7;
public class TryWithResources {
	public static void main(String[] args) {
		try (AutoFechavel af = new AutoFechavel()) {
			System.out.print("Ahh eu aqui. ");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

A saída desse código será: "Ahh eu aqui. Fechou!!!". Demonstrando que após finalizar o bloco try, o método close() é chamado automaticamente.

Podemos também ter duas ou mais variáveis dentro do try. Juntando os dois exemplos, temos:

		try (AutoFechavel af = new AutoFechavel();
				BufferedReader br = new BufferedReader(new FileReader(
						"teste.txt"))) {
			System.out.print("Ahh eu aqui. ");
			String txt = null;
			while ((txt = br.readLine()) != null) {
				System.out.println(txt);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

Como as classes antigas também foram modificadas para implementar a interface AutoCloseable, podemos também utilizar essa funcionalidade em classes que realizam conexão com o banco (ResultSet, PreparedStatement, Connection, ...) e com isso nossa vida fica bem mais fácil!

Pontos importantes:

  1. As variáveis declaradas dentro do try-with-resources são marcadas como final.
  2. A classe da variável declarada deve implementar a interface AutoCloseable
  3. O escopo da variável é somente dentro do bloco try (completo)
  4. As variáveis tem que ter nomes diferentes se estiverem dentro de um mesmo bloco try
  5. Os recursos são iniciados da esquerda pra direita (de acordo com a declaração) e são fechados da direita pra esquerda.
  6. Se o recurso for nulo ele não é fechado
  7. Se um recurso lançar exceção ao fechar, os outros recursos continuarão a serem fechados (exceção suprimida).
  8. Quando as exceções forem suprimidas, você pode recuperá-las utilizando o método: Throwable.getSuppressed()(normalmente dentro do catch)

Um dos problemas comum é atribuir um novo valor para a variável utilizada dentro do try-with-resources:

		try (BufferedReader br = new BufferedReader(new FileReader("teste.txt"))) {
			String txt = null;
			while ((txt = br.readLine()) != null) {
				System.out.println(txt);
			}
			br = new BufferedReader(new FileReader("novoArquivo.txt"));
		} catch (Exception e) {
			e.printStackTrace();
			if (e.getSuppressed() != null) {
				for (Throwable t : e.getSuppressed()) {
					t.printStackTrace();
				}
			}
		}

Na linha 6 estamos atribuindo para uma variável final. Isso vai ocasionar erro de compilação. Na linha 10 temos um exemplo de como recuperar as exceções suprimidas.

Sobre: Thiago Galbiatti Vespa

Thiago Galbiatti Vespa é mestre em Ciências da Computação e Matemática Computacional pela USP e bacharel em Ciências da Computação pela UNESP. Coordenador de projetos do JavaNoroeste, membro do JCP (Java Community Process), consultor Oracle, arquiteto de software de empresas de médio e grande porte, palestrante de vários eventos e colaborador de projetos open source. Possui as certificações: Oracle Certified Master, Java EE 5 Enterprise Architect – Step 1, 2 and 3; Oracle WebCenter Portal 11g Certified Implementation Specialist; Oracle Service Oriented Architecture Infrastructure Implementation Certified Expert; Oracle Certified Professional, Java EE 5 Web Services Developer; Oracle Certified Expert, NetBeans Integrated Development Environment 6.1 Programmer; Oracle Certified Professional, Java Programmer; Oracle Certified Associate, Java SE 5/SE 6