Caelum | Ensino e Inovação - Cursos de Java, Scrum, Ruby on Rails


Generics, inferência de tipos e reificação no Java 7

Por Paulo Silveira em 08/04/07

Muito tem se falado sobre o Java 7 SE e que mudanças na linguagem essa versão poderá trazer. Alex Miller criou um excelente post com muito links para JSRs e blogs sobre as propostas para a linguagem. Peter Ahe publicou também um interessante wish list.

Maneiras alternativas de criarmos coleções usando uma sintaxe mais enxuta já foram discutidas por Stephen Colebourne, Peter Ahe e Rafael Ferreira. Gostaria de salientar que o Java 5 já trouxe alguns métodos interessantes na Collections com essa finalidade. Exemplos são quando queremos criar uma coleção vazia ou com apenas um elemento:

List<String> x = Collections.emptyList();
List<Integer> y = Collections.singletonList(5);

Existem métodos análogos para a criação de conjuntos e mapas. A assinatura do método emptyList é <T> List<T> emptyList(). É interessante que a linguagem infere <T>, descobrindo que nesse primeiro caso T deve ser String. Mas isso nem sempre acontece:

  static void  metodo(List<String> lista) {
    // faz alguma coisa
  }
  
  // dentro do main:
  metodo(Collections.emptyList());

A invocação acima não compila, pois tenta fazer T como Object! Algumas pessoas acham que isso é um bug, mas o pessoal da Sun decidiu por não tentar inferir o tipo em determinadas situações. Na verdade, o compilador só tenta inferir o tipo em dois específicos casos: na clausula de return ou em uma atribuição.

A especificação da linguagem Java tem uma sintaxe especial no caso de você querer indicar qual é o tipo que deve ser utilizado em uma invocação de método genérico:

  metodo(Collections.<String>emptyList());

Pronto! Agora o Java sabe que T deve ser String nessa invocação, e nosso código passa a compilar. Uma sintaxe esdruxula e pouco comum.

Enquanto todo mundo comenta sobre as closures do Java 7, sem dúvida meu principal interesse sobre o Java 7 é a reificação de tipos genéricos, isso é, em tempo de execução, poder determinar os tipos parametrizados de um objeto. Hoje em dia isso não é possível por causa da erasure, que mantém a compatibilidade com o código pré-generics: um objeto não sabe, em tempo de execução, quais são os tipos que foram usados nos seus parâmetros durante sua instanciação. Isso cria algumas clássicas questões nos fóruns, como “porque não posso criar uma array de T?” ou “Porque não posso usar T.class?“. Muitas pessoas consideram até a hipótese de quebrar a compatibilidade binária do Java, e fazem propostas interessantes para resolver esse problema.

Creio que o Java 7 trará muitas novas surpresas, algumas interessantes como as closures, outras infames como o suporte a literais XML dentro da linguagem. Só espero que eles continuem com a premissa do Java, de deixá-la legível e simples, e não façam como no C++, onde todo novo recurso interessante foi adicionado, tornando a linguagem de difícil legibilidade em alguns casos.

  • Share/Bookmark

3 Comments »

  1. Para ficar registrado, outro ponto que gostaria muito de ver implementado no Java sao os literais para metodos, construtores e campos:

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5043025

    Comment by Paulo Silveira — April 16, 2007 @ 12:41 am

  2. Legível e simples? Você ainda acha? :D

    Dá uma olhada na JSR 308…

    Comment by Renato — April 21, 2007 @ 3:41 pm

  3. [...] já havia postado sobre isso quando falei de reificação de tipos parametrizados, mas de uma maneira mais [...]

    Pingback by » Não posso descobrir nem instanciar tipos genéricos! Porque? » blog.caelum.com.br — April 28, 2008 @ 5:38 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment




Caelum | Ensino e Inovação
São Paulo: Rua Vergueiro, 3185, cj. 87, próximo ao Metrô Vila Mariana   |   Tel. (11) 5571-2751
Rio de Janeiro: Rua Senador Dantas, 80, cj. 307/308 - Centro   |   Tel. (21) 2220-4156 ou 2297-0033
Brasília: SCS Qd. 8 Bl. B-50, Sala 521 - Ed. Venâncio 2000   |   Tel. (61) 3039-4222