Java 9 na prática: melhorias na API de Collections e mapa
![Java 9 na prática: melhorias na API de Collections e mapa](https://www.alura.com.br/artigos/assets/code/java-9-na-pratica-melhorias-na-api-de-collections-e-mapa.1725719702.png)
Nos posts anteriores falamos sobre o REPL e a polêmica proposta de inferência de variáveis locais do Java 9. Pra esse terceiro escolhi mostrar uma proposta que já está em andamento e que, sem dúvida alguma, será muito usada em nosso dia a dia.
JEP 269: Convenience Factory Methods for Collections.
Definir APIs da biblioteca para tornar conveniente criar instâncias de coleções e mapas com um pequeno número de elementos, aliviando a dor de não termos coleções literais no Java.
Se você já instalou o REPL, pode testar todos os exemplos de código desse post diretamente por ele.
Entendendo a motivação da proposta
Não é segredo que criar coleções em Java é um processo verboso e chato nem sempre simples. Garantir que elas não sejam modificadas no futuro implica em um pouco mais de código e verbosidade. Quer um exemplo? Uma mapa de IDs e nomes:
Map<Integer, String> users = new HashMap<>(); users.put(1, "Turini"); users.put(2, "Paulo"); users.put(3, "Guilherme"); return Collections.unmodifiableMap(users);
Criamos uma instância da implementação mais comum HashMap
, armazenamos em uma variável local, invocamos o método put
para cada conjunto de chave e valor e por fim, usamos o Collections#unmodifiableMap
pra retornar uma versão não modificável deste mapa. Nada muito complicado, mas foram 5 linhas de código e vários passos para alcançar esse objetivo simples.
![Banner da Escola de Programação: Matricula-se na escola de Programação. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!](assets/alura-matricula-maior-escola-tecnologia-brasil-mais-500-mil-estudantes/matricula-escola-programacao-alura-saiba-mais-versao-mobile.png)
Menos é mais? Nem sempre
Acredite quando eu digo que o problema não está na quantidade de linhas, daria pra fazer isso tudo direto no return com o não muito amado recurso de double brace initialization:
return Collections.unmodifiableMap(new HashMap<>() {{ put(1, "Turini"); put(2, "Paulo"); put(3, "Guilherme"); }});
Se você achou esse código horrível, temos algo em comum. Além de não ser muito recomendado por envolver criação de classes anônimas, o código continua bastante verboso e agora com uma sintaxe esdrúxula. Nem sempre menos linhas de código implicam em um código melhor.
Os frameworks ajudam bastante
Claro que existem diversas alternativas como o Guava que vem nos ajudando bastante com esse trabalho. Em resumo, ele oferece um conjunto de classes utilitárias que complementam as funcionalidades das nossas Collections além de diversos outros recursos interessantes. Usamos bastante aqui nos projetos da Caelum, Alura e Casa do Código. Você encontra, inclusive, diversos exemplos de uso no código fonte do VRaptor 4.
O exemplo do mapa anterior ficaria assim:
return ImmutableMap.of(1,"Turini", 2,"Paulo", 3,"Guilherme");
Legal, não é? Deu uma boa limpada na sintaxe, aproximando um pouco mais das famosas collections literals de linguagens como o Python, Groovy e Scala. Em Groovy, por exemplo, o código seria dessa forma:
def users = ```1:"Turini", 2:"Paulo", 3:"Guilherme"
Por sinal, o Brian Goetz, arquiteto da Oracle, vem falando sobre a possibilidade das collection literals em Java desde antes do Java 8. Ele inclusive já esboçou uma JEP de pesquisa com algumas possibilidades. As features da proposta que vou mostrar neste post é um dos frutos dessa idéia inicial.
JEP 269: Convenience Factory Methods for Collections
Com a introdução dessa proposta do Java 9 finalmente poderemos criar o mapa assim:
return Map.of(1,"Turini", 2,"Paulo", 3,"Guilherme");
Bem parecido com o estilo mais enxuto do Guava. E ainda existem algumas variações de sintaxe para quando você tem mapas um pouco maiores, que precisam ser construídos dinamicamente e etc. Repare:
Map.ofEntries( entry(1, "Turini"), entry(2, "Paulo"), entry(3, "Guilherme"), entry(4, "Sérgio") );
O entry
que usamos aqui é um import estático de um outro factory method criado na interface Map
:
Map.Entry<K,V> entry = Map.entry( K k, V v );
O ganho foi grande, e vai bem além dos Mapas.
Criando listas e sets com os novos métodos
Quantas vezes você usou o Arrays.asList(...)
essa semana? A boa notícia é que finalmente podemos fazer algo parecido diretamente pela interface List
:
List.of("Turini", "Paulo", "Guilherme");
E dá pra fazer o mesmo com a interface Set
. O exemplo de motivação que foi usado na página da proposta é bem legal, mostrando bastante o ganho em legibilidade e verbosidade da nova abordagem comparada com a atual. Essa é uma das formas bastante usada atualmente, sem ajuda de frameworks:
Set<String> set = Collections.unmodifiableSet( new HashSet<>(Arrays.asList("a", "b", "c")) );
Veja que o unmodifiableSet é criado a partir de um novo HashSet
, que por sua vez é criado com a cópia de uma outra Collection. Da forma atual basta fazer um Set.of(...)
e o trabalho estará feito:
Set<String> set = Set.of("a", "b", "c");
Lembrando que elas não podem ser modificadas
Vale lembrar que o objetivo dessa proposta é permitir uma forma fácil de criar instâncias não modificáveis das collections e mapas.
Fornecer factory methods estáticos nas interfaces das coleções e mapas que vão criar instâncias compactas e não-modificáveis.
Pra testar, basta criar uma lista usando o novo método:
jshell> List.of("não", "posso", "ser", "editada"); $1 ==> ```não, posso, ser, editada
E depois experimente adicionar um novo elemento:
jshell> $1.add("posso?"); | java.lang.UnsupportedOperationException thrown | at Collections$UnmodifiableCollection.add (Collections.java:1056) | at (#2:1)
Uma UnsupportedOperationException
será lançada. Se você percorrer os elementos da lista verá que estão todos lá, da mesma forma que foi criada:
jshell> $1.forEach(System.out::println); não posso ser editada
Outras novidades
Em breve quero escrever sobre a proposta do jigsaw, que permite a modularização da plataforma e o JDK. Passei o final de semana brincando com ele e vi que já está em uma etapa bem interessante. Se tiver curioso sobre algum outro assunto, não deixe de me contar nos comentários.
Ah, e falando em Collections, na Alura agora temos um novo curso do Paulo mostrando tudo que você precisa pra dominar as principais classes dessa fundamental API. Também falamos bastante disso em no curso presencial de Java e Orientação a Objetos da Caelum.
E você, o que achou dessa novidade? Tem gostado das propostas da linguagem?