Esse artigo faz parte da revista Java Magazine edição 27. Clique aqui para ler todos os artigos desta edição

Atenção: por essa edição ser muito antiga não há arquivo PDF para download.Os artigos dessa edição estão disponíveis somente através do formato HTML. 

Byte Code

Migrando para o Java 5

Parte 1: Usando Novas Sintaxes e APIs

Saiba como migra para o J2SE 5.0 com segurança, introduzindo criteriosamente o uso de autoboxing, enums, varags, for estendido e anotações.

 

A versão 5.0 do Java foi lançada em outubro de 2004 há quase um ano, mas muitos desenvolvedores ainda não migraram de fato, rodando suas aplicações no novo runtime e explorando as novidades de linguagem e de APIs nos seus projetos. Um dos motivos é que ainda não quis DAE esse passo não encontrou dificuldades, pois todas as APIs e ferramentas que usa continuam suportando versões anteriores da J2SE. Mas isto está mudando.

Quem acompanha o progresso das JSRs em definição – muitas implementadas de forma aberta no portal Java.net – sabe que a nova geração de APIs traz requisito obrigatório o J2SE 5.0. Essa lista já inclui as JSRs 181 (WebServices), 220 (EJB 3.0), 222 (JAXB 2.0), 224 (JAX-RPC 2.0), 224 (J2EE 5.0), 245 (JSP 2.1), 250 (Anotaçoes Comuns), 252 (JSF 1.2), e 269 (API para Anotaçoes). Sendo que- algumas, como JAXB 2.0 e EJB 3.0, já estão em fase adiantada e podem já estar finalizadas quando ler esta matéria.

Essas novas tecnologias não somente precisam do runtime 5.0 do Java (JRE) para funcionar, mas também exigem que o desenvolvedor conheça as novidades do J2SE 5.0. As APIs atualizadas fazem amplo uso dos novos recursos da linguagem, e a demanda para aproveitar as melhorias de todas essas APIs logo criará um forte incentivo para a migração.

Este artigo aborda a adoção efetiva do J2SE 5.0. Vamos explorar questões que surgem apenas com experiência – quando realmente começamos a escrever novas aplicações, ou modificar código existente para tirar proveito das melhorias. E mostraremos a caminho das pedras naqueles casos onde a prática revela algumas surpresas (perigosas ou benéficas) menos evidentes na teoria.

Vamos abordar todas as melhorias de linguagem, com exceção de tipos genéricos, que serão vistos em profundidade na edição seguinte. Para cada melhoria, incluímos uma seção “Como migrar” que mostra como fazer as mudanças de forma mais fácil e segura. O quadro “Planejando a migração” discorre um pouco mais sobre estratégias de migração, especialmente sobre as opções de adotar a nova linguagem em projetos novos ou existentes. Mas vamos pôr mãos à obra, examinado cada novidade da linguagem.

 

Autoboxing

O autoboxing elimina boa parte do incômodo do sistema de tipos “OO híbrido” do Java, que além de objetos inclui suporte a tipos primitivos. Por exemplo, quais das seguintes sintaxes são validas no Java 5?

1.     Integer obj=10; int prim=obj;

2.     Math.sin(obj);prim=hashMap.get(prim);

3.     prim=prim+obj;obj=obj+prim;

4.     Strings=prim.toString();

 

Todas com exceção da última. Em 1, temos os casos mais triviais de conversão de primitivo para objeto e vice-versa (autoboxing e auto-unboxing).

Em 2, vemos como o autoboxing também funciona quando tentamos usar objetos onde um primitivo é esperado, como passar Integer para sin(double) ou int para get(Object).

Em 3, vemos como autoboxing até simula a sobrecarga de operadores para os objetos que encapsulam números. Podemos utilizar os tipos wrapper (Integer, Double, etc.) em expressões aritméticas e lógicas, e o autoboxing se encarregará de extrair os valores primitivos de forma apropriada para cada operação.

A única sintaxe não suporta é a 4. Além de ter utilidade duvidosa, suportá-la criaria complicações na sintaxe da linguagem, já que teria também de ser suportada para literais, como em “99.toString()”. Para detalhes das implicações desta sintaxe, veja o quadro “Novas sintaxes: considerações teóricas”.

 

Como migrar:

·         Expressões corretas de autoboxing e auto-unboxing podem ser eliminadas sem nenhum risco: X:intValue() pode ser substituído por X; new Integer(Y), por Y.

Ao migrar o código para tirar proveito das facilidades de autoboxing e auto-unboxing, tenha cuidado com códigos que possam estar utilizando sintaxes imprecisas para as literais. Por exemplo, em new Double(5) a literal 5 é um int, portanto uma simples eliminação do tipo wrapper produziria (ao se aciona o autoboxing) um Integer e não um Double! O certo seria usar uma literal com 5.0 ou 5d, que tem o tipo Double (isso já era uma boa pratica mesmo antes do Java 5). Se o seu código possuir inconsistências dessa espécie, uma conversão para autoboxing sem o devido cuidado poderá gerar ClassCastExceptions.

Por outro lado, isso só acontecerá se em outro lugar do programa você tiver um código como doublex=((Double)y).doubleValue(), onde y é um Object que recebeu aquele valor que antes era um Double(5) e agora é um Integer(5). Se o autoboxing tiver sido aplicado de forma ampla, tanto nas operações de boxing quanto de unboxing, não haverá problemas. Este último exemplo, se migrado para double x=y, não gera erro mesmo se y for um Integer, pois este unboxing não exige uma conversão para Double.

Outra dica: se os wrappers estão sendo utilizados para colocar valores primitivos em coleções, faça a migração para coleções, faça a migração para coleções genéricas antes de adotar o autoboxing. Por exemplo, se você tiver List lista; lista.add(new Double(5)), arrisca-se em incorrer no problema anterior ao migrar, pois add(5) colocará um Integer na lista. Mas se você primeiro adotar os tipos genéricos – Lista<Double>lista – então a alteração posterior para autoboxing torna-se segura. O compilador aceitará lista.add(5), fazendo a promoção de int para Double e produzindo o mesmo que add(5.0) ou add((Double)5).

 

Varargs

O recurso de argumentos variáveis (varargs) é excelente para simplificar métodos que suportam um numero arbitrário de dados de entrada, o que normalmente exige passar esses dados por arrays. Por exemplo, digamos que é necessário implementar um método Max() que funcione para uma lista arbitrária de argumentos, de forma a evitar expressões complexas como Math.max(a,Math.max(b,Math.max(c,d))). As seguintes versões são alternativas tradicionais para isso:

1.     Sobrecargas

      double max (double a, double b);

      double max (double a, double b, double c);

      double max (double a, double b, double c, double d);

     

2.     Argumento array

      double max (double[]values);

 

Em 1 criamos diversas sobrecargas do método, uma para cada numero de argumentos (aridade). Isso permite invocações simples como max(1,2,3), mas evidentemente só podemos suportar um número limitado de argumentos. A interface fica poluída com tantas sobrecargas do método e há duplicação de código.

Em 2 temos um método que recebe um array de parâmetros, o que resolve os problemas anteriores, mas complica as invocações. Por exemplo, para descobrir qual é a maior das variáveis a e b, precisaríamos escrever um atrapalhado Max(new Double[]{a,b}).

No Java 5.0, a versão 3 a seguir resolve todos os problemas. Temos um método único, sem repetição de código ou poluição da interface com sobrecargas, e podemos fazer invocações simples como Max(a,b);

3.     Argumento variável

      ...

Quer ler esse conteúdo completo? Tenha acesso completo