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:
- As variáveis declaradas dentro do try-with-resources são marcadas como final.
- A classe da variável declarada deve implementar a interface AutoCloseable
- O escopo da variável é somente dentro do bloco try (completo)
- As variáveis tem que ter nomes diferentes se estiverem dentro de um mesmo bloco try
- Os recursos são iniciados da esquerda pra direita (de acordo com a declaração) e são fechados da direita pra esquerda.
- Se o recurso for nulo ele não é fechado
- Se um recurso lançar exceção ao fechar, os outros recursos continuarão a serem fechados (exceção suprimida).
- 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.
Muito bom o seu poste use ele hoje e solucionei um bug dos grandes.
Desenvolvedor Pleno