Criando e inicializando listas em Java e Groovy
Crie e inicialize uma lista de inteiros, primeiro em Java e depois em Groovy.
Gosto muito da linguagem de programação Groovy. Gosto porque, no final das contas, gosto de Java, embora Java às vezes pareça desajeitado. E como gosto muito de Java, não acho muitas outras linguagens JVM especialmente atraentes. Kotlin, Scala e Clojure, por exemplo, não se parecem muito com Java, buscando suas próprias perspectivas sobre o que constitui uma boa linguagem de programação. Groovy é diferente; na minha opinião, Groovy é o antídoto perfeito para aquelas situações em que um programador que gosta de Java só precisa de algo um pouco mais flexível, compacto e às vezes até direto.
Um bom exemplo é a estrutura de dados List, que é usada para armazenar uma lista ordenada de números, strings ou objetos e permite ao programador iterar por esses itens de maneira eficiente. Especialmente para pessoas que escrevem e mantêm scripts, "eficiência" envolve principalmente expressões claras e breves que não exigem muita cerimônia que obscureça a intenção do código.
Instale Java e Groovy
Groovy é baseado em Java e também requer instalação de Java. Uma versão recente e decente do Java e do Groovy pode estar nos repositórios da sua distribuição Linux. Caso contrário, você pode instalar o Groovy seguindo estas instruções. Uma boa alternativa para usuários de Linux é o SDKMan, que pode ser usado para obter várias versões de Java, Groovy e muitas outras ferramentas relacionadas. Para este artigo, uso as versões do SDK de:
- Java: versão 11.0.12-open do OpenJDK 11
- Groovy: versão 3.0.8
De volta ao problema
Existem várias maneiras de instanciar e inicializar listas em Java desde que foram introduzidas pela primeira vez (acho que foi o Java 1.5, mas por favor, não me cite). Duas formas interessantes atuais envolvem duas bibliotecas diferentes: java.util.Arrays e java.util.List.
Usarjava.util.Arrays
java.util.Arrays define o método estático asList(), que pode ser usado para criar uma lista que é apoiada por um array e, portanto, também imutável, embora seus elementos são mutáveis. Aqui está em ação:
var a1 = Arrays.asList(1,2,3,4,5,6,7,8,9,10); // immutable list of mutable elements
System.out.println("a1 = " + a1);
System.out.println("a1 is an instance of " + a1.getClass());
// output is
// a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// a1 is an instance of class java.util.Arrays$ArrayList
a1.set(0,0); // succeeds
System.out.println("a1 = " + a1); // output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a1.add(11); // fails producing
// Exception in thread "main" java.lang.UnsupportedOperationException
System.out.println("a1 = " + a1); // not reached
Usarjava.util.List
java.util.List define o método estático of(). Isso pode ser usado para criar uma lista imutável com elementos que podem ou não ser imutáveis, dependendo se o os itens da lista de elementos são imutáveis. Aqui está esta versão em ação:
var a2 = List.of(1,2,3,4,5,6,7,8,9,10);
System.out.println("a2 = " + a2);
System.out.println("a2 is an instance of " + a2.getClass());
// output is
// a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// a2 is an instance of class java.util.ImmutableCollections$ListN
a2.set(0,0); // fails producing
// Exception in thread "main" java.lang.UnsupportedOperationException
System.out.println("a2 = " + a2); // not reached
a2.add(11); // also fails for same reason if above two lines commented out
System.out.println("a2 = " + a2); // not reached
Portanto, posso usar Arrays.asList() ou List.of() se quiser uma lista que não pode ser aumentada (ou reduzida) e pode ou pode não possuem elementos alteráveis.
Se eu quiser uma lista mutável inicializada, provavelmente recorrerei ao uso dessas listas imutáveis como argumentos para um construtor de lista, por exemplo:
var a1 = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
System.out.println("a1 = " + a1);
System.out.println("a1 is an instance of " + a1.getClass());
// output is
// a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// a1 is an instance of class java.util.ArrayList
a1.set(0,0);
System.out.println("a1 = " + a1);
//output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a1.add(11);
System.out.println("a1 = " + a1);
// output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Observe que Arrays.AsList() foi usado para inicializar o novo ArrayList
Talvez seja só eu, mas isso parece muita teoria - a necessidade de estar ciente da situação dos detalhes de java.util.Arrays ou java.util.List —apenas para criar e inicializar uma lista mutável de números inteiros, embora a instrução real usada não seja excessivamente "cerimonial". Aqui está novamente, apenas para referência:
var a1 = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
A abordagem Groovy
Aqui está a versão Groovy do acima:
def a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
println "a1 = $a1"
println "a1 is an instance of ${a1.getClass()}"
// output is
// a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// a1 is an instance of class java.util.ArrayList
a1[0] = 0
println "a1 = $a1"
// output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a1 << 11
println "a1 = $a1"
// output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
À primeira vista, o Groovy usa a palavra-chave def em vez de var. Também sei que posso criar uma representação de lista colocando uma lista de coisas – neste caso, números inteiros – entre colchetes. Além disso, a instância da lista criada é exatamente o que eu quero: uma instância mutável de ArrayList.
Agora, talvez seja só eu, de novo, mas o que foi dito acima parece ser muito mais simples - sem lembrar os resultados semi-imutáveis retornados por .of() ou .asList() e compensando por eles. Também é bom poder me referir a um elemento específico da lista usando colchetes com um valor de índice entre eles, em vez da chamada do método set(), e que o <<
é anexado ao final de uma lista para que eu não precise usar a chamada de método add(). Além disso, você notou a falta de ponto e vírgula? Sim, no Groovy, eles são opcionais. E, finalmente, observe o uso da interpolação de strings, com $variable ou $ {expression} dentro de uma string entre aspas fornecendo essa capacidade.
Há mais coisas acontecendo “nos bastidores” no mundo Groovy. Essa definição é um exemplo de tipagem dinâmica (o padrão no Groovy) versus a tipagem estática do Java. Na linha de definição do Groovy, o tipo de a1 é inferido em tempo de execução a partir do tipo da expressão avaliada no lado direito. Agora todos nós sabemos que as linguagens de programação dinâmicas nos dão grande poder e que com grande poder surgem muitas boas oportunidades para errar. Mas para programadores que não gostam de digitação dinâmica, o Groovy oferece a opção de digitação estática.
Recursos incríveis
O site Apache Groovy que mencionei no início tem muita documentação excelente. Outro excelente recurso do Groovy é o Sr. Haki. E um bom motivo para aprender Groovy é continuar aprendendo Grails, que é uma estrutura web full-stack maravilhosamente produtiva construída sobre componentes excelentes como Hibernate, Spring Boot e Micronaut.
Este artigo é dedicado ao meu querido amigo Anil Mukhi, que faleceu em 3 de janeiro de 2022. Obrigado, Anil, por me dar a oportunidade de aprender tanto sobre Groovy, Grails e dados de corridas de cavalos.