Generics, inferência de tipos e reificação no Java 7
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 infereT
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](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6293352), 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:
```java
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.