Java 9 introdujo nuevos métodos de fábrica para listas List.of
:
List<String> strings = List.of("first", "second");
¿Cuál es la diferencia entre la opción anterior y la nueva? Es decir, cuál es la diferencia entre esto:
Arrays.asList(1, 2, 3);
y esto:
List.of(1, 2, 3);
Respuestas:
Arrays.asList
devuelve una lista mutable mientras que la lista devuelta porList.of
es inmutable :Arrays.asList
permite elementos nulos mientrasList.of
que no:contains
se comporta de manera diferente con nulos:Arrays.asList
devuelve una vista de la matriz pasada, por lo que los cambios a la matriz también se reflejarán en la lista. PorqueList.of
esto no es cierto:fuente
List.contains(Object o)
javadoc del ' : "Lanza [...] NullPointerException - si el elemento especificado es nulo y esta lista no permite elementos nulos (opcional)". O de la extensa introducción de la interfaz que pocos leen: "Algunas implementaciones de colección tienen restricciones sobre los elementos que pueden contener"List.of
no volver algúnImmutableList
tipo, su nombre real es sólo un detalle de implementación no pública. Si era público y alguien lo lanzaba deList
nuevo, ¿dónde estaba la diferencia? ¿Dónde está la diferencia conArrays.asList
, que devuelve unaList
implementación no pública , que arroja una excepción al intentaradd
oremove
, o la lista devuelta por laCollections.unmodifiableList
que no permite ninguna modificación? Se trata de contratos especificados en laList
interfaz. Las interfaces de Colecciones con métodos opcionales siempre fueron impuras OOP desde Java 1.2…Las diferencias entre
Arrays.asList
yList.of
Vea JavaDocs y esta charla de Stuart Marks (o versiones anteriores).
Usaré lo siguiente para los ejemplos de código:
Inmutabilidad estructural (O: inmodificabilidad)
Cualquier intento de cambiar estructuralmente
List.of
resultará en unUnsupportedOperationException
. Eso incluye operaciones como agregar , configurar y eliminar . Sin embargo, puede cambiar el contenido de los objetos en la lista (si los objetos no son inmutables), por lo que la lista no es "completamente inmutable".Este es el mismo destino para las listas no modificables creadas con
Collections.unmodifiableList
. Solo esta lista es una vista de la lista original, por lo que puede cambiar si cambia la lista original.Arrays.asList
no es completamente inmutable, no tiene restriccionesset
.De manera similar, cambiar la matriz de respaldo (si la mantiene presionada) cambiará la lista.
La inmutabilidad estructural viene con muchos efectos secundarios relacionados con la codificación defensiva, la concurrencia y la seguridad que están más allá del alcance de esta respuesta.
Hostilidad nula
List.of
y cualquier colección desde Java 1.5 no se permitenull
como elemento. Intentar pasarnull
como un elemento o incluso una búsqueda resultará en unNullPointerException
.Dado que
Arrays.asList
es una colección de 1.2 (el marco de colecciones), permitenull
s.Forma serializada
Dado que
List.of
se introdujo en Java 9 y las listas creadas por este método tienen su propia forma serializada (binaria), no se pueden deserializar en versiones anteriores de JDK (sin compatibilidad binaria ). Sin embargo, puede eliminar / serializar con JSON, por ejemplo.Identidad
Arrays.asList
llamadas internasnew ArrayList
, lo que garantiza la desigualdad de referencia.List.of
depende de la implementación interna. Las instancias devueltas pueden tener igualdad de referencia, pero como esto no está garantizado, no puede confiar en ellas.Vale la pena mencionar que las listas son iguales (vía
List.equals
) si contienen los mismos elementos en el mismo orden, independientemente de cómo fueron creadas o qué operaciones soportan.Implementación (advertencia: los detalles pueden cambiar según las versiones)
Si el número de elementos en la lista de
List.of
es 2 o menos, los elementos se almacenan en campos de una clase especializada (interna). Un ejemplo es la lista que almacena 2 elementos (fuente parcial):De lo contrario, se almacenan en una matriz de forma similar a
Arrays.asList
.Eficiencia de tiempo y espacio
Las
List.of
implementaciones que se basan en el campo (tamaño <2) funcionan un poco más rápido en algunas operaciones. Como ejemplos,size()
puede devolver una constante sin obtener la longitud de la matriz ycontains(E e)
no requiere una sobrecarga de iteración.La construcción de una lista no modificable vía
List.of
también es más rápida. Compare el constructor anterior con 2 asignaciones de referencia (e incluso la de una cantidad arbitraria de elementos) paraque crea 2 listas más otros gastos generales. En términos de espacio, ahorra el
UnmodifiableList
envoltorio más algunos centavos. En última instancia, los ahorros en elHashSet
equivalente son más convincentes.Tiempo de conclusión: utilícelo
List.of
cuando desee una lista que no cambie yArrays.asList
cuando desee una lista que pueda cambiar (como se muestra arriba).fuente
Arrays.asList
no es completamente mutable.asList.add(1);
lanza unUnsupportedOperationException
.List.of
tiempo que la gente quiera llamarcontains
y no ser sorprendido por una NullPointerException.Resumamos las diferencias entre List.of y Arrays.asList
List.of
se puede utilizar mejor cuando el conjunto de datos es menor y sin cambios, mientras queArrays.asList
se puede utilizar mejor en el caso de un conjunto de datos grande y dinámico.List.of
ocupa mucho menos espacio de sobrecarga porque tiene una implementación basada en el campo y consume menos espacio de pila, tanto en términos de sobrecarga fija como por elemento. mientras queArrays.asList
ocupa más espacio de sobrecarga porque durante la inicialización crea más objetos en el montón.La colección devuelta por
List.of
es inmutable y, por lo tanto, segura para subprocesos, mientras que la colección devuelta porArrays.asList
es mutable y no segura para subprocesos. (Las instancias de colección inmutables generalmente consumen mucha menos memoria que sus contrapartes mutables).List.of
no permite elementos nulos mientras queArrays.asList
permite elementos nulos .fuente
Arrays.asList
versusList.of
, dado que el primero es literalmente una envoltura alrededor de una matriz. Al menos, la implementación de OpenJDK parece tener una sobrecarga extremadamente pequeña. De hecho,List.of
necesitaría hacer copias de cualquier matriz pasada, por lo que, a menos que la matriz en sí vaya a ser GC pronto, parecería queList.of
tiene una huella de memoria significativamente mayor.List.of(x)
yList.of(x, y)
son más eficientes porque no asignan matrices en absolutoList.of
métodos no son necesarios para devolver listas nuevas cada vez. Estas listas tienen una identidad no especificada, por lo que podría haber almacenamiento en caché o deduplicación o escalarización manejada en el nivel de JVM. Si no está en esta versión, quizás en la siguiente. Está permitido por el contrato. Por el contrario,Array.asList
depende de la identidad de la matriz que está pasando, ya que la lista resultante es una vista mutable en la matriz, que refleja todos los cambios bidireccionales.Aparte de las respuestas anteriores, hay ciertas operaciones en las que ambos
List::of
yArrays::asList
difieren:Más sobre colecciones :: singletonList Vs. Lista de
fuente