Vea JavaDocs y esta charla de Stuart Marks (o versiones anteriores).
Usaré lo siguiente para los ejemplos de código:
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
Inmutabilidad estructural (O: inmodificabilidad)
Cualquier intento de cambiar estructuralmenteList.of
resultará en un UnsupportedOperationException
. 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 restricciones set
.
listOf.set(1, "a"); // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a"); // modified unmodif! unmodif is not truly unmodifiable
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 permite null
como elemento. Intentar pasar null
como un elemento o incluso una búsqueda resultará en un NullPointerException
.
Dado que Arrays.asList
es una colección de 1.2 (el marco de colecciones), permite null
s.
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
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 internas new 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.
asList1 == asList2; // false
listOf1 == listOf2; // true or false
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.
asList.equals(listOf); // true i.f.f. same elements in same order
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):
static final class List2<E> extends AbstractImmutableList<E> {
private final E e0;
private final E e1;
List2(E e0, E e1) {
this.e0 = Objects.requireNonNull(e0);
this.e1 = Objects.requireNonNull(e1);
}
}
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 y contains(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) para
Collections.unmodifiableList(Arrays.asList(...));
que 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 el HashSet
equivalente son más convincentes.
Tiempo de conclusión: utilícelo List.of
cuando desee una lista que no cambie y Arrays.asList
cuando desee una lista que pueda cambiar (como se muestra arriba).