Já há rumores sobre Java 9, mas para quem, assim como eu, ainda estava no Java 6 e se atrasou um pouco para conferir as novidades do Java 7, vale a pena dar uma conferida nas novas facilidades introduzidas na linguagem e como elas podem melhorar o código dos seus projetos.
Algumas mudanças entram na categoria chamada de Syntactic Sugar, o que, resumidamente, são novidades introduzidas somente a nível de linguagem para facilitar a vida do programador, sendo em momento de compilação revertidas à sintaxe padrão. Um exemplo anterior de uma melhoria ao estilo Syntactic Sugar introduzida no Java 5 é o autoboxing e unboxing (conversão automática entre valores primitivos e seus respectivos wrapper objects).
Vou apresentar aqui as seguintes novidades: switch com String, novidades nos numéricos, tratamento de múltiplas exceções, try-with-resources e diamond syntax.
switch com String
Finalmente, em sua sétima versão, a linguagem Java introduziu a possibilidade de utilizar objetos String em um switch, que já era possível há tempos em outras linguagens. Até a versão 6, só eram possíveis os tipos byte, char, short, int e seus wrappers (Byte, Character, Short, Integer).
Segue abaixo um exemplo simples utilizando String:
String mesString = "janeiro"; int mesNum = 0; switch(mesString) { case "janeiro" : mesNum = 1; break; case "fevereiro" : mesNum = 2; break; case "março" : mesNum = 3; break; }
Novidades nos numéricos
As novidades do Java 7 para os valores numéricos são duas: Possibilidade de adicionar separadores em números com underscore (_) e simplificação na conversão de números a partir de sistema binário ou hexadecimal.
Seguem exemplos até Java 6:
long umBilhao = 1000000000; // Difícil de contar os zeros int dezEmBinario = Integer.parseInt("1010", 2); int trintaEmHexadecimal = Integer.parseInt("1e", 16);
Seguem exemplos com Java 7:
long umBilhao = 1_000_000_000L; // Fácil de contar os zeros int dezEmBinario = 0b1010; // Bem mais simples int trintaEmHexadecimal = 0x1e; // Bem mais simples
Tratamento de múltiplas exceções
Até o Java 6, a captura de exceções lançadas tinha dois formatos possíveis: Capturar um tipo de Exception abrangendo o próprio tipo e todas as suas subclasses, ou capturar especificamente a Exception desejada, uma por catch.
A partir do Java 7, uma terceira forma de captura é possível: Exceções hierarquicamente equivalentes (sem herança entre si) podem ser associadas juntamente em um único catch, sendo separadas por um pipe (|), o que é extremamente vantajoso no caso de se desejar um tratamento comum para variados tipos de exceção.
Segue abaixo um exemplo até Java 6:
try { executarRegraCabulosa(); } catch (Tipo1Exception e) { System.err.println("Mensagem para exceções do tipo 1, 2 ou 3"); } catch (Tipo2Exception e) { System.err.println("Mensagem para exceções do tipo 1, 2 ou 3"); } catch (Tipo3Exception e) { System.err.println("Mensagem para exceções do tipo 1, 2 ou 3"); } catch (Tipo4Exception e) { System.err.println("Mensagem para exceção do tipo 4"); }
E abaixo um exemplo com Java 7:
try { executarRegraCabulosa(); } catch (Tipo1Exception|Tipo2Exception|Tipo3Exception e) { System.err.println("Mensagem para exceções do tipo 1, 2 ou 3"); } catch (Tipo4Exception e) { System.err.println("Mensagem para exceção do tipo 4"); }
Outra pequena novidade no tratamento de exceção envolve a prática comum de tratar uma exceção e lançá-la para segundo tratamento na camada superior. Com a adição da palavra-chave final, o compilador entende que o tipo de exceção é o mesmo que foi capturado e não precisará de tratamento mais genérico na camada superior, mantendo assim a possibilidade de uma captura genérica sem obrigar as camadas superiores a fazerem o mesmo.
public void metodoQueLancaExcecao() throws Tipo1Exception, Tipo2Exception{ try { executarRegraCabulosa(); // Lança Tipo1Exception ou Tipo2Exception } catch (final Exception e) { ... ... ... throw e; // É interpretado que o tipo lançado aqui continua sendo o tipo capturado } }
try-with-resources
Seguindo a mesma linha de diminuir a quantidade de código, o novo recurso try-with-resources elimina a necessidade de fechar manualmente (chamando close()) objetos de classes de algum tipo de recurso de IO.
Java 7 inclui uma nova interface java.lang.AutoCloseable e algumas mudanças na classe já existente java.lang.Throwable. Todas as instâncias de classes que implementem AutoCloseable podem a partir dessa nova versão serem incluídas numa espécie de parametrização do bloco try que irá garantir a chamada do close().
Abaixo segue um exemplo até Java 6:
InputStream is = null; try { is = url.openStream(); OutputStream out = new FileOutputStream(file); try { byte[] buf = new byte[4096]; int len; while ((len = is.read(buf)) >= 0) out.write(buf, 0, len); } catch (IOException iox) { } finally { try { out.close(); } catch (IOException closeOutx) { } } } catch (FileNotFoundException fnfx) { } catch (IOException ioe) { } finally { try { if (is != null) is.close(); } catch (IOException closeInx) { } }
E abaixo o mesmo código utilizando try-with-resources com Java 7. Observe que na parametrização do try um ou mais recursos podem ser abertos e os blocos finally não têm mais a necessidade de existir visto que sua única função era fechar os recursos abertos, o que agora é feito automaticamente.
try(OutputStream out = new FileOutputStream(file); InputStream is = url.openStream()) { byte[] buf = new byte[4096]; int len; while ((len = is.read(buf)) >= 0) out.write(buf, 0, len); } catch (FileNotFoundException fnfx) { } catch (IOException ioe) { }
Conforme mencionado um pouco antes, a classe java.lang.Throwable também sofreu alterações nessa nova versão da linguagem. Dois novos métodos e um novo construtor tratam o novo conceito de exceções suprimidas. Quando algum trecho de código interno a um bloco que usa try-with-resources lança alguma exceção, as exceções eventualmente lançadas por erros no fechamento dos recursos parametrizados no try serão suprimidas dentro da exceção lançada no código do bloco.
Por exemplo, no código abaixo, caso ocorra erro no fechamento do recurso e também ocorra erro na chamada do método da linha 4, o bloco catch da linha 6 irá capturar uma LeituraException através da qual poderão ser obtidas as eventuais FileNotFoundException ou IOException conforme linha 8.
try(OutputStream out = new FileOutputStream(file); InputStream is = url.openStream()) { processarLeitura(is); // Pode lançar uma LeituraException } catch (Exception e) { e.getSuppressed(); // Um array de possíveis exceções suprimidas }
Para mais detalhes sobre essas mudanças na classe Throwable recomendo esse link.
Diamond syntax
Essa é uma novidade bem simples e bem útil. Elimina uma redundância de tipagem imposta pelo uso de generics desde sua origem no Java 5.
Em vez de precisar escrever assim:
Map<String, Object> mapa = new HashMap<String, Object>();
Agora você só precisa escrever assim:
Map<String, Object> mapa = new HashMap<>();
Não falei que era simples!?
Conclusão
Com essas e outras novidades não apresentadas aqui, é possível facilitar um tanto a vida, reduzir o código e torná-lo mais robusto e elegante. Há ainda outras novidades envolvendo API de I/O chamada New I/O ou NIO.2, API JDBC, alterações na própria JVM, Class Loader, dentre outras que podem vir a ser exploradas aqui no blog em próximos posts.
Forte abraço e até a próxima!
Nenhum comentário:
Postar um comentário