Java 9 na prática: melhorias na API de Collections e mapa

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.

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?


Tags:

15 Comentários

  1. Guilherme 27/06/2016 at 09:13 #

    Bem interessante, vai reduzir a verbosidade de maneira considerável.

  2. Igor Cavalcante 27/06/2016 at 15:36 #

    Java, Bem vindo aos anos 2000!

  3. Rodrigo Turini 27/06/2016 at 23:26 #

    Pois é! O java 8 finalmente abriu caminho pra esse tipo de evolução na linguagem. Desde os default methods muitas APIs, da própria linguagem e dos frameworks, tem melhorado bastante.

  4. Leonardo Villela 05/07/2016 at 09:19 #

    O Java vem surpreendendo cada vez mais, o Java 8 de fato deu inicio as mudanças, otímo post Rodrigo e estou bem ancioso para o proximo sobre a proposta do jigsaw, abraço.

  5. Jader Lucas 11/07/2016 at 13:27 #

    Esperando jigsaw!!

  6. Jhonatan Serafim 12/07/2016 at 20:19 #

    Ótimo post Rodrigo. Agora é aguardar o Java 9 =)

  7. astaldy de jesus goncalves 13/07/2016 at 05:04 #

    astaldy de jesus e gostaria de receber mas dicas sobre este curso
    e também gostaria de participar num destes cursos

  8. Jhonatan Morais 13/07/2016 at 08:59 #

    Post muito bem escrito e totalmente didático. Obrigado pelo conhecimento. Até a proxíma.

  9. Rodrigo Turini 16/07/2016 at 09:19 #

    valeu, pessoal! em breve sai o de jigsaw e outros que já estão na wishlist (;

  10. Rodrigo Turini 16/07/2016 at 09:20 #

    @astaldy, nos mande um contato contanto um pouco mais sobre o que você já conhece pra conseguirmos te indicar o curso ideal, o que acha?

    https://www.caelum.com.br/contato/

  11. André Franco 21/07/2016 at 15:39 #

    Excelente post.
    Eu que sempre tive dificuldades para usar o MAPS, com esta nova forma de trabalhar ficou bem mais fácil.

  12. Gustavo Camargo 27/07/2016 at 11:51 #

    Show!

  13. Helcio da Silva 02/01/2017 at 12:43 #

    Ótimo post Rodrigo!

  14. Rodrigo Turini 08/10/2017 at 12:32 #

    pra quem gostou e quer acompanhar, saiu um post no blog da caelum sobre o mínimo que você deve saber de Java 9
    http://blog.caelum.com.br/o-minimo-que-voce-deve-saber-de-java-9/
    e o livro da casa do código, lançado junto com a nova versão da linguagem
    https://www.casadocodigo.com.br/products/livro-java9

Deixe uma resposta