O Java 7, lançado em Julho, além de reviver mudanças no Java também trouxe novas características afim de tornar a linguagem um pouco mais simples e menos verbosa, ou seja, as instruções podem ser escritas com um volume menor de código.
Nós da Globalcode adoramos novidades, ainda mais relacionada ao Java, usamos e incentivamos nossos alunos e clientes a experimentarem o Java 7. Nesse post vou comentar sobre as características do novo bloco try do Java.
Para começar, primeiro, vamos analisar uma demonstração simples de um programa Java que lê o conteúdo de arquivo texto linha a linha:
Nós da Globalcode adoramos novidades, ainda mais relacionada ao Java, usamos e incentivamos nossos alunos e clientes a experimentarem o Java 7. Nesse post vou comentar sobre as características do novo bloco try do Java.
Para começar, primeiro, vamos analisar uma demonstração simples de um programa Java que lê o conteúdo de arquivo texto linha a linha:
import java.io.*; public class DemoTryAntigo { public static void main(String[] args) { FileReader in = null; BufferedReader buff = null; try { in = new FileReader("/home/yaw/teste.txt"); //caminho do arquivo buff = new BufferedReader(in, 1024); StringBuilder builder = new StringBuilder(); String s = null; while ((s = buff.readLine()) != null) { builder.append(s).append("\n"); } System.out.println("Conteudo do arquivo:\n\n"+builder); } catch(IOException iox) { System.out.println("Falha ao ler arquivo: "+iox.getMessage()); } finally { if (buff != null) { try { buff.close(); } catch(IOException bufx) { System.out.println("Falha ao fechar buffer: "+bufx.getMessage()); } } if (in != null) { try { in.close(); } catch(IOException inx) { System.out.println("Falha ao fechar arquivo: "+inx.getMessage()); } } } } }
Nenhuma complexidade nesse exemplo, o ponto negativo é o excesso de código (linhas 22 a 35) no bloco finally necessário para liberar os recursos de I/O utilizados na leitura do arquivo. O programa escrito dessa forma compila e funciona no Java 7, mas a partir do Java 7 podemos tirar proveito do try-with-resources: um recurso é um objeto que deve ser encerrado quando o bloco try for concluído. Veja como ficaria o mesmo programa utilizando essa funcionalidade do Java 7:
import java.io.*; public class DemoNovoTry { public static void main(String[] args) { try (FileReader in = new FileReader("/home/yaw/teste.txt"); BufferedReader buff = new BufferedReader(in, 1024)) { StringBuilder builder = new StringBuilder(); String s = null; while ((s = buff.readLine()) != null) { builder.append(s).append("\n"); } System.out.println("Conteudo do arquivo:\n\n"+builder); } catch(IOException iox) { System.out.println("Falha ao ler arquivo: "+iox.getMessage()); } } }
O código ficou bem mais limpo! Uma regra importante sobre o try-with-resources é que o objeto (recurso) definido no try deve implementar ou interface java.lang.AutoCloseable (nova) ou java.io.Closeable, qualquer outro conteúdo o compilador não irá aceitar. No exemplo demonstrado ambas FileReader e BufferedReader implementam AutoCloseable, essa foi uma das mudanças na API de I/O ocorridas no Java7.
Na verdade, nos bastidores, o Java faz o trabalho “sujo” de implementar o bloco de finalização para garantir que os recursos sejam encerrados, omitindo o código aos programadores. O Java transforma cada recurso declarado no try em uma variável final e, define um bloco try-finally aninhado a declaração desse recurso. Outra característica importante é que em casos com mais de um recurso definido no try (o nosso exemplo cai nessa situação) o Java encerra os recursos na ordem inversa em que são definidos, garantindo que todos os recursos serão devidamente encerrados. A seguir o código que o compilador do Java 7 utiliza para gerar o byte code:
Na verdade, nos bastidores, o Java faz o trabalho “sujo” de implementar o bloco de finalização para garantir que os recursos sejam encerrados, omitindo o código aos programadores. O Java transforma cada recurso declarado no try em uma variável final e, define um bloco try-finally aninhado a declaração desse recurso. Outra característica importante é que em casos com mais de um recurso definido no try (o nosso exemplo cai nessa situação) o Java encerra os recursos na ordem inversa em que são definidos, garantindo que todos os recursos serão devidamente encerrados. A seguir o código que o compilador do Java 7 utiliza para gerar o byte code:
import java.io.*; public class DemoNovoTry { public static void main(String[] args) { try { final FileReader in = new FileReader("/home/yaw/teste.txt"); /*synthetic*/ Throwable primaryException0$ = null; try { final BufferedReader buff = new BufferedReader(in, 1024); /*synthetic*/ Throwable primaryException1$ = null; try { StringBuilder builder = new StringBuilder(); String s = null; while ((s = buff.readLine()) != null) { builder.append(s).append("\n"); } System.out.println("Conteudo do arquivo:\n\n" + builder); } catch (/*synthetic*/ final Throwable t$) { primaryException1$ = t$; throw t$; } finally { if (buff != null) if (primaryException1$ != null) try { buff.close(); } catch (Throwable x2) { primaryException1$.addSuppressed(x2); } else buff.close(); } } catch (/*synthetic*/ final Throwable t$) { primaryException0$ = t$; throw t$; } finally { if (in != null) if (primaryException0$ != null) try { in.close(); } catch (Throwable x2) { primaryException0$.addSuppressed(x2); } else in.close(); } } catch (IOException iox) { System.out.println("Falha ao ler arquivo: " + iox.getMessage()); } } }
Analisando cuidadosamente o código acima, é possível identificar as mudanças realizadas na estrutura de exceções do Java 7: o método addSuppressed na classe Throwable, que permite que uma exceção secundária seja vinculada a outra exceção primária. Veja o trecho com o finally do BufferedReader (linhas 22 a 32), ao fechar o buffer o programa verifica se existe alguma exceção gerada durante a leitura do buffer, dessa forma se ocorrer alguma exceção durante o close do buffer essa será vinculada a exceção primária lançada do try.
Outro método novo em Throwable é o getSuppressed, que retorna um array com exceções vinculadas a exceção principal, um novo construtor da classe também foi criado no Java 7.
A API do JDBC, versão 4, foi ajustada no Java 7 para respeitar o AutoCloseable. A seguir um programa Java abre uma conexão com uma base de dados MySQL e executa uma instrução SQL.
(Importante: ao testar garanta que o driver esteja configurado; o caminho, usuário e senha do banco de dados estejam corretos; e a existência da tabela clientes)Outro método novo em Throwable é o getSuppressed, que retorna um array com exceções vinculadas a exceção principal, um novo construtor da classe também foi criado no Java 7.
A API do JDBC, versão 4, foi ajustada no Java 7 para respeitar o AutoCloseable. A seguir um programa Java abre uma conexão com uma base de dados MySQL e executa uma instrução SQL.
import java.sql.*; public class DemoTryJDBC { public static void main(String[] args) throws SQLException, Exception { Class.forName("com.mysql.jdbc.Driver"); String query = "select nome, cpf from clientes"; String urlDB = "jdbc:mysql://localhost:3306/testdb"; try (Connection con = DriverManager.getConnection(urlDB,"user","user"); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(query)) { while (rs.next()) { String nome = rs.getString("nome"); String cpf = rs.getString("cpf"); System.out.printf("Nome:%s\t Cpf:%s %n", nome, cpf); } } } }
Outra novidade do Java 7, ainda no escopo do bloco try, é a possibilidade de definir o mesmo tratamento de erro para diversos tipos de exceções utilizando o multicatch. O próximo o utilizo a API de reflexão do Java para criar uma String, veja que o catch determina o mesmo tratamento para as exceções: ClassNotFoundException, InstantiationException ou IllegalAccessException.
public class DemoMulticatch { public static void main(String[] args) { Object o = null; try { Class clazz = Class.forName("java.lang.String"); o = clazz.newInstance(); System.out.println(o.getClass()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { System.err.println("Erro na criação do objeto: "+ex.getMessage()); } } }
Sobre o multicatch, uma regra importante é que o compilador não aceita a declaração utilizando exceções polimórficas, com relacionamento via herança. Por exemplo, não é permitido utilizar o tipo Exception dentro dessa instrução catch. Também não é permitido definir checked exceptions que não são lançadas dentro do try, no exemplo acima uma IOException não seria aceita dentro do catch. Para uncheked exceptions (Runtime) o compilador é flexível, seria permitido declarar uma NullPointerException naquele catch.
Durante o TDC2011 edição São Paulo e Florianópolis, falamos bastante sobre o Java 7! Na próxima edição, em Goiânia, não poderia ser diferente, no sábado (29/10) vai rolar a palestra Tirando proveito dos novos recursos do Java 7 na trilha Java.
O Java 7 disponibiliza outros recursos que deixam a linguagem mais sucinta, para saber mais sobre essas outras novidades ou características relacionadas acesse os links abaixo:
O Java 7 disponibiliza outros recursos que deixam a linguagem mais sucinta, para saber mais sobre essas outras novidades ou características relacionadas acesse os links abaixo:
- Lançamento do JDK 7 no TDC2011 em São Paulo;
- Artigo no InfoQ Brasil - Java 7: Modificações na Linguagem, em detalhes e exemplos;
- Palestra no TDC2011 Florianópolis: JDK7 - Modificações da Linguagem;
- Minicurso Gratuito: JDK7 - Modificações na Linguagem;
- Tutorial da Oracle sobre try-with-resources;
[]s
Eder Magalhães
www.yaw.com.br
twitter.com/youandwe
twitter.com/edermag
Comentários