docs - documentation java 9
¿Cuál es la diferencia entre List.of y Arrays.asList? (3)
Java 9 introdujo un nuevo método 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);
Las diferencias entre
Arrays.asList
y
List.of
Vea los JavaDocs y esta talk de Stuart Marks (o versiones anteriores de la misma).
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
estructuralmente
List.of
dará como resultado una
UnsupportedOperationException
.
Eso incluye operaciones como
agregar
,
establecer
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 una restricción en el
set
.
listOf.set(1, "a"); // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a"); // modified unmodif! unmodif is not truly unmodifiable
Del mismo modo, cambiar la matriz de respaldo (si la mantiene) 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.
Nula hostilidad
List.of
y cualquier colección desde Java 1.5 no permiten
null
como elemento.
Intentar pasar
null
como elemento o incluso una búsqueda dará como resultado una
NullPointerException
.
Dado que
Arrays.asList
es una colección de 1.2 (el Marco de colecciones), permite
null
.
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
Forma serializada
Como
List.of
se ha introducido 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 des / serializar con JSON, por ejemplo.
Identidad
Arrays.asList
llama internamente a la
new ArrayList
, 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 él.
asList1 == asList2; // false
listOf1 == listOf2; // true or false
Vale la pena mencionar que las listas son iguales (a través de
List.equals
) si contienen los mismos elementos en el mismo orden, independientemente de cómo se crearon o qué operaciones admiten.
asList.equals(listOf); // true i.f.f. same elements in same order
Implementación (advertencia: los detalles pueden cambiar sobre 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 manera similar a
Arrays.asList
.
Eficiencia de tiempo y espacio
Las implementaciones de
List.of
que se basan en campos (tamaño <2) funcionan ligeramente 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 sobrecarga de iteración.
Construir una lista no modificable a través de
List.of
también es más rápido.
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, guarda el envoltorio de la
UnmodifiableList
Modificación más algunos centavos.
En última instancia, los ahorros en el equivalente de
HashSet
son más convincentes.
List.of
conclusión: use
List.of
cuando desee una lista que no cambie y
Arrays.asList
cuando desee una lista que pueda cambiar (como se muestra arriba).
Vamos a resumir las diferencias entre List.of y Arrays.asList
-
List.of
puede usar mejor cuando el conjunto de datos es menor y sin cambios, mientras queArrays.asList
se puede usar 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 deList.of
dinámico, tanto en términos de sobrecarga fija como por elemento. mientras queArrays.asList
ocupa más espacio de arriba 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 inmutable generalmente consumen mucha menos memoria que sus contrapartes mutables). -
List.of
no permite elementos nulos , mientras queArrays.asList
permite elementos nulos .
Arrays.asList
devuelve una lista mutable mientras que la lista devuelta por
List.of
es
immutable
:
List<Integer> list = Arrays.asList(1, 2, null);
list.set(1, 10); // OK
List<Integer> list = List.of(1, 2, 3);
list.set(1, 10); // Fails with UnsupportedOperationException
Arrays.asList
permite elementos nulos, mientras que
List.of
no:
List<Integer> list = Arrays.asList(1, 2, null); // OK
List<Integer> list = List.of(1, 2, null); // Fails with NullPointerException
contains
comporta de manera diferente con nulos:
List<Integer> list = Arrays.asList(1, 2, 3);
list.contains(null); // Returns false
List<Integer> list = List.of(1, 2, 3);
list.contains(null); // Fails with NullPointerException
Arrays.asList
devuelve una vista de la matriz aprobada, por lo que los cambios en la matriz también se reflejarán en la lista.
Para
List.of
esto no es cierto:
Integer[] array = {1,2,3};
List<Integer> list = Arrays.asList(array);
array[1] = 10;
System.out.println(list); // Prints [1, 10, 3]
Integer[] array = {1,2,3};
List<Integer> list = List.of(array);
array[1] = 10;
System.out.println(list); // Prints [1, 2, 3]