Artigo Java Magazine 28 - Migrando para o Java 5

Saiba como incorporar a mais sofisticada novidade de linguagem do J2SE 5.0 nos seus sistemas, começando com um tutorial completo.

Esse artigo faz parte da revista Java Magazine edição 28. 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.

Migrando para o Java 5

Parte 2: Tipos Genéricos

Como incorporar a mais sofisticada novidade de linguagem do J2SE 5.0 nos seus sistemas, começando com um tutorial completo

 

O suporte a tipos genéricos é a principal novidade de linguagem do Java 5, a mais evidente e mais comentada – e um dos maiores incentivos para a migração para a nova versão. Por outro lado, também será o recurso que levará mais tempo para ser utilizado no seu pleno potencial: não só corretamente, mas da forma mais eficaz e elegante, em todos os casos em que pode contribuir para a melhoria de um software.

O artigo Fazendo a Migração nesta coluna conclui a série iniciada na edição anterior, com dicas e orientações práticas para a adoção deste poderoso recurso do novo Java. Mas para quem ainda não está familiarizado com os genéricos, começamos com um Tutorial que apresenta todos os conceitos básicos necessários, e revisita o tema para incluir tópicos mais avançados do que os já explorados em artigos anteriores sobre genéricos

 

Tutorial de Genéricos

Tipos genéricos devem ser vistos antes de mais nada como uma evolução natural da linguagem Java. Isto porque levam adiante e mais a fundo princípios que existem desde a primeira versão da tecnologia. O mais importante destes princípios é o sistema estático de verificação de tipos, idealizado para detectar erros como conversões ilegais, ou a invocação de métodos inexistentes num objeto em tempo de compilação. Isto é muito mais robusto do que permitir a compilação e só muito mais tarde, ao executar o trecho de código incorreto, ocorrer uma exceção ou outro comportamento indesejado.

Cada linguagem naturalmente tem suas vantagens, e algumas pessoas discordam que tipos estáticos sejam uma boa idéia. Para quem acha que declarar o tipo de todas as variáveis dá mais trabalho do que traz benefícios, existem linguagens dinamicamente tipadas. Mas se você escolheu Java, certamente concorda que os tipos estáticos são boa coisa: afinal, trata-se de uma das características mais fundamentais da tecnologia. Gostar do Java e não gostar de tipos estáticos é como gostar de ópera e não gostar da língua italiana.

Os tipos genéricos nada mais são que os tipos estáticos levados às últimas conseqüências. A idéia é que deveríamos incluir, em declarações estáticas, ainda mais informações de tipo. Por exemplo, uma linguagem sem tipagem estática declararia algo como “var documentos”, negando ao compilador qualquer informação sobre o conteúdo da variável. Já uma linguagem estaticamente tipada, como o Java “tradicional” (pré-Java 5), declararia “List documentos”, informando ao compilador que tal variável é uma lista – o que permite validar determinadas operações (como invocação de métodos, atribuições e conversões). Finalmente, no Java 5, podemos declarar “List<Documento> documentos”, o que fornece ao compilador ainda mais detalhes sobre o uso dessa variável. Agora, o compilador conhece também o tipo de todos os elementos que podem ser adicionados à lista, o que permite realizar ainda mais verificações automáticas.

 

O contrato dos tipos genéricos

Na linguagem Java tradicional, o sistema de tipos garante que nenhuma conversão ilegal seja feita. Todas as conversões implícitas (que não exigem typecasts) funcionam garantidamente, sem jamais gerar problemas. Já para as conversões explícitas – forçadas com typecasts – o Java garante que as únicas possibilidades sejam que ou a conversão funciona ou gera uma ClassCasException, mas que nunca causa qualquer outro problema (como corrupção da memória, core-dumps/crashes etc.).

Com os tipos genéricos, a linguagem pode dar garantias ainda mais fortes. Segundo o que podemos chamar de princípio fundamental dos tipos genéricos, um programa que não possui nenhum typecast e que não gera nenhum warning de compilação é type-safe, ou seja, jamais irá gerar uma ClassCastexception.

Mas note o requisito dos warnings. Com o javac, você deve compilar com javac –Xlint:unsafe (ou –Xlint:all): esta opção gera warnings para determinadas operações inseguras que o Java 5 tolera por motivo de compatibilidade, e que tipicamente são necessárias para conviver com código legado (veja mais no tópido “Tipos brutos”).

 

Tipos genéricos

Na essência dos tipos genéricos, temos o recurso de parâmetros de tipo, que podem ser aplicados tanto a interfaces e classes quanto a métodos:

 

class Par<C, V> {

  private C chave;

  private V valor;

  Par (C chave, V valor) {this.chave = chave;this.valor = valor;}

  void setValor (V valor) {this.valor = valor;}

  V getValor () {return valor;}

  void setChave (C chave) {this.chave = chave;}

  C getChave () {return chave;}

}

  Par<Interger,String> p = new Par<Interger,String>(55, “Brasil”);

  String pais = p.getValor();

  p.setChave(“Brasil”);//Erro!

 

A declaração Par<C, V> define um tipo genérico Par, ou seja, um tipo com pelo menos um parâmetro de tipo (no caso temos dois: C e V). Dentro da classe Par, podemos usar os mesmos parâmetros de tipo nas declarações de variáveis locais, atributos, parâmetros, e retorno.

Quando declaramos Par<Interger, String> p, usamos um tipo parametrizado – que teve seus parâmetros de tipo satisfeitos, no caso pelos tipos Interger (argumento para C) e String (para V). Esta instanciação de tipo genérico para tipo parametrizado pode ser compreendida como uma simples “busca e substituição” no código da classe genérica. É como se tivéssemos criado uma cópia da classe Par com um atributo Interger chave, um método void setChave(Interger chave) e assim por diante. Vistos dessa forma, os tipos genéricos são simples. Basta habituar-se à nova sintaxe.

 

Métodos genéricos

Métodos individuais podem definir seus próprios parâmetros de tipo:

 

static <T> T Max (T a, T b) {

  return a.compareTo(b)>=0? " [...] continue lendo...

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados