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.asListdevuelve una lista mutable mientras que la lista devuelta porList.ofes inmutable :Arrays.asListpermite elementos nulos mientrasList.ofque no:containsse comporta de manera diferente con nulos:Arrays.asListdevuelve una vista de la matriz pasada, por lo que los cambios a la matriz también se reflejarán en la lista. PorqueList.ofesto 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.ofno volver algúnImmutableListtipo, su nombre real es sólo un detalle de implementación no pública. Si era público y alguien lo lanzaba deListnuevo, ¿dónde estaba la diferencia? ¿Dónde está la diferencia conArrays.asList, que devuelve unaListimplementación no pública , que arroja una excepción al intentaraddoremove, o la lista devuelta por laCollections.unmodifiableListque no permite ninguna modificación? Se trata de contratos especificados en laListinterfaz. Las interfaces de Colecciones con métodos opcionales siempre fueron impuras OOP desde Java 1.2…Las diferencias entre
Arrays.asListyList.ofVea 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.ofresultará 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.asListno 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.ofy cualquier colección desde Java 1.5 no se permitenullcomo elemento. Intentar pasarnullcomo un elemento o incluso una búsqueda resultará en unNullPointerException.Dado que
Arrays.asListes una colección de 1.2 (el marco de colecciones), permitenulls.Forma serializada
Dado que
List.ofse 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.asListllamadas internasnew ArrayList, lo que garantiza la desigualdad de referencia.List.ofdepende 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.ofes 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.ofimplementaciones 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.oftambié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
UnmodifiableListenvoltorio más algunos centavos. En última instancia, los ahorros en elHashSetequivalente son más convincentes.Tiempo de conclusión: utilícelo
List.ofcuando desee una lista que no cambie yArrays.asListcuando desee una lista que pueda cambiar (como se muestra arriba).fuente
Arrays.asListno es completamente mutable.asList.add(1);lanza unUnsupportedOperationException.List.oftiempo que la gente quiera llamarcontainsy no ser sorprendido por una NullPointerException.Resumamos las diferencias entre List.of y Arrays.asList
List.ofse puede utilizar mejor cuando el conjunto de datos es menor y sin cambios, mientras queArrays.asListse puede utilizar mejor en el caso de un conjunto de datos grande y dinámico.List.ofocupa 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.asListocupa más espacio de sobrecarga porque durante la inicialización crea más objetos en el montón.La colección devuelta por
List.ofes inmutable y, por lo tanto, segura para subprocesos, mientras que la colección devuelta porArrays.asListes mutable y no segura para subprocesos. (Las instancias de colección inmutables generalmente consumen mucha menos memoria que sus contrapartes mutables).List.ofno permite elementos nulos mientras queArrays.asListpermite elementos nulos .fuente
Arrays.asListversusList.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.ofnecesitarí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.oftiene una huella de memoria significativamente mayor.List.of(x)yList.of(x, y)son más eficientes porque no asignan matrices en absolutoList.ofmé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.asListdepende 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::ofyArrays::asListdifieren:Más sobre colecciones :: singletonList Vs. Lista de
fuente