Inicialización de la lista de Java en una línea

1. Introducción

En este tutorial rápido, investigaremos cómo podemos inicializar una lista usando frases breves.

2. Crear a partir de una matriz

Podemos crear una Lista a partir de una matriz y gracias a los literales de matriz podemos inicializarlos en una línea:

List list = Arrays.asList(new String[]{"foo", "bar"});

Podemos confiar en el mecanismo de varargs para manejar la creación de la matriz. Con eso, podemos escribir un código más conciso y legible:

@Test public void givenArraysAsList_thenInitialiseList() { List list = Arrays.asList("foo", "bar"); assertTrue(list.contains("foo")); }

La instancia de resultado de este código implementa la interfaz List pero no es java.util.ArrayList ni LinkedList . En cambio, es una lista respaldada por la matriz original que tiene dos implicaciones.

Aunque, el nombre de la clase resulta ser ArrayList pero en el paquete java.util.Arrays .

2.1. Tamaño fijo

La instancia de resultado de Arrays.asList tendrá un tamaño fijo:

@Test(expected = UnsupportedOperationException.class) public void givenArraysAsList_whenAdd_thenUnsupportedException() { List list = Arrays.asList("foo", "bar"); list.add("baz"); }

2.2. Referencia compartida

La matriz original y la lista comparten las mismas referencias a los objetos:

@Test public void givenArraysAsList_whenCreated_thenShareReference(){ String[] array = {"foo", "bar"}; List list = Arrays.asList(array); array[0] = "baz"; assertEquals("baz", list.get(0)); }

3. Crear desde una secuencia (Java 8)

Podemos convertir fácilmente un Stream en cualquier tipo de Colección.

Por lo tanto, con los métodos de fábrica para Streams , podemos crear e inicializar listas en una línea:

@Test public void givenStream_thenInitializeList(){ List list = Stream.of("foo", "bar") .collect(Collectors.toList()); assertTrue(list.contains("foo")); }

Debemos marcar aquí que Collectors.toList () no garantiza la implementación exacta de la List devuelta .

No existe un contrato general sobre la mutabilidad, serialización o seguridad de subprocesos de la instancia devuelta. Por lo tanto, nuestro código no debería depender de ninguna de estas propiedades.

Algunas fuentes destacan que Stream.of (…) .collect (…) puede tener una mayor huella de memoria y rendimiento que Arrays.asList (), pero en casi todos los casos, es una microoptimización tal que hay poca diferencia.

4. Métodos de fábrica (Java 9)

En JDK 9, se han introducido varios métodos de fábrica convenientes para las colecciones:

List list = List.of("foo", "bar", "baz"); Set set = Set.of("foo", "bar", "baz");

Un detalle importante es que las instancias devueltas son inmutables . Más allá de eso, los métodos de fábrica tienen varias ventajas en cuanto a eficiencia de espacio y seguridad de hilos.

Este tema se explora más en este artículo.

5. Inicialización de doble riostra

En varios lugares, podemos encontrar un método llamado 'inicialización de doble llave' que se parece a:

@Test public void givenAnonymousInnerClass_thenInitialiseList() { List cities = new ArrayList() {{ add("New York"); add("Rio"); add("Tokyo"); }}; assertTrue(cities.contains("New York")); }

El nombre 'inicialización de doble llave' es bastante engañoso. La sintaxis puede parecer compacta y elegante, pero oculta peligrosamente lo que está pasando bajo el capó.

En realidad, no hay un elemento de sintaxis de 'doble llave' en Java, esos son dos bloques formateados intencionalmente de esta manera.

Con las llaves externas, declaramos una clase interna anónima que será una subclase de ArrayList . Dentro de estas llaves, podemos declarar los detalles de nuestra subclase.

Como de costumbre, podemos usar bloques de inicialización de instancias y de ahí proviene el par interno de llaves.

La brevedad de esta sintaxis es tentadora, sin embargo, se considera un anti-patrón.

Para leer más sobre la inicialización de doble abrazadera, eche un vistazo a nuestro artículo aquí.

6. Conclusión

Modern Java ofrece varias opciones para crear una colección en una línea. El método que elegimos depende casi exclusivamente de las preferencias personales, más que del razonamiento técnico.

Una conclusión importante es que, aunque parece elegante, el anti-patrón de inicialización de clase interna anónima (también conocido como 'doble llave') tiene muchos efectos secundarios negativos .

Como siempre, el código está disponible en GitHub.