Creando e inicializando listas en Java y Groovy
Cree e inicialice una lista de números enteros, primero en Java y luego en Groovy.
Me gusta mucho el lenguaje de programación Groovy. Me gusta porque, al final, me gusta Java, aunque a veces Java parezca torpe. Y como me gusta tanto Java, no encuentro muchos otros lenguajes JVM especialmente atractivos. Kotlin, Scala y Clojure, por ejemplo, no se parecen mucho a Java y persiguen sus propias perspectivas sobre lo que constituye un buen lenguaje de programación. Groovy es diferente; En mi opinión, Groovy es el antídoto perfecto para aquellas situaciones en las que un programador al que le gusta Java sólo necesita algo un poco más flexible, compacto y, a veces, incluso sencillo.
Un buen ejemplo es la estructura de datos Lista, que se utiliza para contener una lista ordenada de números, cadenas u objetos, y permite al programador iterar a través de esos elementos de manera eficiente. Especialmente para las personas que escriben y mantienen guiones, la "eficiencia" se trata principalmente de expresiones claras y breves que no requieren mucha ceremonia que oscurezca la intención del código.
Instalar Java y Groovy
Groovy está basado en Java y también requiere una instalación de Java. Es posible que haya una versión reciente y decente de Java y Groovy en los repositorios de su distribución de Linux. De lo contrario, puede instalar Groovy siguiendo estas instrucciones. Una buena alternativa para los usuarios de Linux es SDKMan, que puede usarse para obtener múltiples versiones de Java, Groovy y muchas otras herramientas relacionadas. Para este artículo, utilizo las versiones del SDK de:
- Java: versión 11.0.12 abierta de OpenJDK 11
- Maravilloso: versión 3.0.8
Volver al problema
Ha habido varias formas de crear instancias e inicializar listas en Java desde que se introdujeron por primera vez (creo que era Java 1.5, pero no me cite). Dos formas interesantes actuales implican dos bibliotecas diferentes: java.util.Arrays y java.util.List.
Utilice java.util.Arrays
java.util.Arrays define el método estático asList(), que se puede utilizar para crear una lista respaldada por una matriz y, por lo tanto, también es inmutable, aunque sus elementos son mutables. Aquí está en acción:
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
Utilice java.util.List
java.util.List define el método estático of(). Esto se puede utilizar para crear una lista inmutable con elementos que pueden o no ser inmutables, dependiendo de si el Los elementos de la lista de elementos son inmutables. Aquí está esta versión en acción:
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
Entonces, puedo usar Arrays.asList() o List.of() si quiero una lista que no pueda ampliarse (ni reducirse) y que pueda o pueda No tener elementos modificables.
Si quiero una lista mutable inicializada, probablemente recurriría al uso de esas listas inmutables como argumentos para un constructor de listas, por ejemplo:
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]
Tenga en cuenta que Arrays.AsList() se usó para inicializar el nuevo ArrayList
Tal vez sea solo yo, pero esto parece una gran cantidad de teoría: la necesidad de ser consciente de la situación de los detalles de java.util.Arrays o java.util.List. —solo para crear e inicializar una lista mutable de números enteros, aunque la declaración real utilizada no es demasiado "ceremonial". Aquí está de nuevo, sólo como referencia:
var a1 = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
El enfoque maravilloso
Aquí está la versión Groovy de lo anterior:
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]
De un vistazo, Groovy utiliza la palabra clave def en lugar de var. También sé que puedo crear una representación de lista poniendo una lista de cosas (en este caso, números enteros) entre paréntesis. Además, la instancia de lista así creada es precisamente lo que quiero: una instancia mutable de ArrayList.
Quizás sea solo yo, de nuevo, pero lo anterior parece ser mucho más simple: no es necesario recordar los resultados semiinmutables devueltos por .of() o .asList() . y compensarlos. También es bueno que pueda hacer referencia a un elemento específico de la lista usando los corchetes con un valor de índice entre ellos, en lugar de la llamada al método set(), y que el <<
El operador se agrega al final de una lista para que no tenga que usar la llamada al método add(). Además, ¿notaste la falta de punto y coma? Sí, en Groovy son opcionales. Y finalmente, observe el uso de la interpolación de cadenas, con la $variable o $ {expresión} dentro de una cadena entre comillas dobles que proporciona esa capacidad.
Hay más cosas sucediendo "bajo las sábanas" en el mundo Groovy. Esa definición es un ejemplo de tipificación dinámica (el valor predeterminado en Groovy) versus la tipificación estática de Java. En la línea de definición de Groovy, el tipo de a1 se infiere en tiempo de ejecución a partir del tipo de expresión evaluada en el lado derecho. Ahora todos sabemos que los lenguajes de programación dinámicos nos dan un gran poder y que un gran poder conlleva muchas buenas oportunidades para equivocarnos. Pero para los programadores a los que no les gusta la escritura dinámica, Groovy ofrece la opción de escritura estática.
Recursos maravillosos
El sitio Apache Groovy que mencioné al principio tiene mucha documentación excelente. Otro excelente recurso de Groovy es el Sr. Haki. Y una muy buena razón para aprender Groovy es continuar y aprender Grails, que es un marco web de pila completa maravillosamente productivo construido sobre excelentes componentes como Hibernate, Spring Boot y Micronaut.
Este artículo está dedicado a mi querido amigo Anil Mukhi, quien falleció el 3 de enero de 2022. Gracias, Anil, por darme la oportunidad de aprender tanto sobre Groovy, Grails y los datos de las carreras de caballos.