¿Cuál es la diferencia entre List.of y Arrays.asList?

6 minutos de lectura

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);

  • Ver también esto hablar por Stuart “Beaker” Marks.

    – usuario1803551

    5 oct 2017 a las 11:40

  • @ user1803551 Aunque entiendo su frustración, este razonamiento podría sentar un precedente realmente no deseado. Mucho de las preguntas aquí tienen una respuesta que está ‘claramente establecida’ (dependiendo de cómo se defina esto). Le insto a que lleve esta discusión a meta, pero estoy bastante seguro de que tal discusión ya debería existir (y espero que alguien pueda encontrarla y vincularla 🙂

    – Dimitris Fasarakis Hilliard

    5 de octubre de 2017 a las 13:23

  • @ user1803551 Javadocs no menciona la diferencia entre los detalles de implementación de estos dos métodos (como el consumo de espacio o el rendimiento). Creo que a la gente también le gustaría saber estos detalles.

    – Zheka Kozlov

    5 oct 2017 a las 13:33

  • @ZhekaKozlov La respuesta aceptada y súper votada tampoco. ¿Qué te dice eso acerca de los estándares aceptados? incluso tiene menos información que en los documentos (serialización, identidad, pedido). En todo caso, presente una solicitud a OpenJDK para agregar esa información.

    – usuario1803551

    6 de octubre de 2017 a las 3:20

  • Esta pregunta se está discutiendo en meta.

    – Dimitris Fasarakis Hilliard

    6 de octubre de 2017 a las 7:15

avatar de usuario
ZhekaKozlov

Arrays.asList devuelve una lista mutable mientras que la lista devuelta por List.of es inmutable:

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 List.of no:

List<Integer> list = Arrays.asList(1, 2, null); // OK
List<Integer> list = List.of(1, 2, null); // Fails with NullPointerException

contains se comporta de manera diferente con valores 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 pasada, por lo que los cambios en la matriz también se reflejarán en la lista. Para List.of esto no es verdad:

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]

  • Que una lista se comporte de manera diferente en función de cómo está construida no me parece muy orientado a objetos. Tal vez si List.of devolviera un tipo ImmutableList, esto tendría sentido. Esta es una abstracción muy permeable aquí.

    – Sandy Chapman

    5 de octubre de 2017 a las 11:22


  • No soy un desarrollador de Java, así que tómalo como una observación casual. Posiblemente haya una buena razón para que el comportamiento difiera, pero si tuviera un método que devolviera un List como el ejemplo, la interfaz no sería suficiente para saber si obtendré una excepción de tiempo de ejecución si la reviso. para nulos. Del mismo modo, un cambio en la implementación de ese método podría afectar el código distante del sitio de llamada de mi método si esa verificación ocurre en otro lugar. @Nicolai

    – Sandy Chapman

    5 de octubre de 2017 a las 11:52

  • @SandyChapman, este podría ser un comportamiento inesperado para algunos (¿o para la mayoría?), Pero es un comportamiento documentado. Desde el List.contains(Object o)‘s javadoc : “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”

    – Aarón

    5 de octubre de 2017 a las 14:04


  • @Aaron bueno, al menos es una abstracción con fugas bien documentada 🙂

    – Sandy Chapman

    5 oct 2017 a las 18:26

  • @Sandy Chapman: List.of lo hace devolver algunos ImmutableList tipo, su nombre real es solo un detalle de implementación no público. Si fuera público y alguien lo echase a List de nuevo, ¿dónde estaba la diferencia? ¿Dónde está la diferencia con Arrays.asListque devuelve un valor no público List implementación, que arroja una excepción al intentar add o removeo la lista devuelta por Collections.unmodifiableList que no permite ninguna modificación en absoluto? Se trata de contratos especificados en el List interfaz. Las interfaces de Colecciones con métodos opcionales siempre fueron OOP impuras desde Java 1.2…

    – Holger

    6 de octubre de 2017 a las 6:32

avatar de usuario
usuario1803551

Las diferencias entre Arrays.asList y List.of

Ver el JavaDocs y esto hablar por Stuart Marks (o versiones anteriores del mismo).

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 estructuralmente cambio List.of resultará en un UnsupportedOperationException. Eso incluye operaciones tales como agregar, establecer y retirar. 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. Sólo 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 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.

Hostilidad nula

List.of y cualquier colección desde Java 1.5 no permite null como elemento. intentando pasar null como un elemento o incluso una búsqueda resultará en un NullPointerException.

Ya que Arrays.asList es una colección de 1.2 (The Collections Framework), permite nulls.

listOf.contains(null);  // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null);  // allowed

formulario serializado

Ya 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 (no compatibilidad binaria). Sin embargo, puede deserializar/deserializar con JSON, por ejemplo.

Identidad

Arrays.asList llamadas internas new ArrayListque garantiza la desigualdad de referencia.

List.of depende de la implementación interna. Las instancias devueltas pueden tener igualdad de referencia, pero dado que esto no está garantizado, no puede confiar en ello.

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 con 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

los List.of las implementaciones basadas en campos (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 sobrecarga de iteración.

Construyendo 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, te ahorras el UnmodifiableList envoltorio más algunos centavos. En última instancia, los ahorros en el HashSet equivalentes son más convincentes.


Tiempo de conclusión: uso List.of cuando quieres una lista que no cambia y Arrays.asList cuando desee una lista que pueda cambiar (como se muestra arriba).

  • Para las personas que se preguntan por qué existe esta respuesta, vean esto.

    – usuario1803551

    06/10/2017 a las 14:36

  • Arrays.asList no es totalmente mutable. asList.add(1); lanza un UnsupportedOperationException.

    – mapeadores

    06/10/2017 a las 20:44


  • “Nulo hostil” es una gran manera de decirlo. Prácticamente no puedo usar List.of cada vez que la gente quiera llamar contains y no se sorprenda con una NullPointerException.

    – Noúmeno

    26 de febrero de 2020 a las 6:08

Resumamos las diferencias entre Lista de y Arreglos.asList

  1. List.of se puede usar mejor cuando el conjunto de datos es menor y no cambia, mientras que Arrays.asList se puede usar mejor en el caso de un conjunto de datos grande y dinámico.

  2. List.of ocupa mucho menos espacio de sobrecarga porque tiene una implementación basada en campo y consume menos espacio de almacenamiento dinámico, tanto en términos de sobrecarga fija como por elemento. tiempo Arrays.asList ocupa más espacio de sobrecarga porque durante la inicialización crea más objetos en el montón.

  3. Colección devuelta por List.of es inmutable y, por lo tanto, seguro para subprocesos, mientras que Collection devuelto por Arrays.asList es mutable y no es seguro para subprocesos. (Las instancias de colección inmutable generalmente consumen mucha menos memoria que sus contrapartes mutables).

  4. List.of no permite nulo elementos mientras Arrays.asList permite nulo elementos.

  • “Las instancias de colección inmutables generalmente consumen mucha menos memoria que sus contrapartes mutables”. – ¿En realidad? ¿Le importaría elaborar un poco sobre eso? ¿Quiere decir porque se pueden compartir de manera segura, o quiere decir que las instancias mismas se pueden implementar de manera más eficiente de alguna manera?

    – hulk

    5 de octubre de 2017 a las 9:15

  • @Hulk El que responde tiene razón sobre la eficiencia del espacio. Vea la charla de Stuart Marks: youtu.be/q6zF3vf114M?t=49m48s

    – Zheka Kozlov

    5 de octubre de 2017 a las 9:34

  • @ZhekaKozlov Eso parece ser cierto en general, pero soy muy escéptico de que sea cierto cuando se habla de Arrays.asList versus List.of, dado que el primero es literalmente solo un envoltorio alrededor de una matriz. Al menos Implementación de OpenJDK parece tener una sobrecarga extremadamente pequeña. En realidad, List.of necesitaría hacer copias de cualquier matriz pasada, por lo que, a menos que la matriz en sí se vaya a GC pronto, parecería que List.of tiene una huella de memoria significativamente mayor.

    – Chris Hayes

    5 de octubre de 2017 a las 9:40

  • @ChrisHayes Al menos List.of(x) y List.of(x, y) son más eficientes porque no asignan matrices en absoluto

    – Zheka Kozlov

    5 oct 2017 a las 10:20

  • @Hulk: no olvides que el List.of No se requiere que los métodos devuelvan nuevas listas 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 en esta versión, quizás en la siguiente. Está permitido por el contrato. A diferencia de, Array.asList depende de la identidad de la matriz que está pasando, ya que la lista resultante es una vista mutable en la matriz, lo que refleja todos los cambios bidireccionales.

    – Holger

    6 de octubre de 2017 a las 6:39

avatar de usuario
Vishwa Ratna

Además de las respuestas anteriores, hay ciertas operaciones en las que ambos List::of y Arrays::asList diferir de:

+----------------------+---------------+----------+----------------+---------------------+
|      Operations      | SINGLETONLIST | LIST::OF | ARRAYS::ASLIST | JAVA.UTIL.ARRAYLIST |
+----------------------+---------------+----------+----------------+---------------------+
|          add         |       ❌      |     ❌  |        ❌      |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|        addAll        |       ❌      |     ❌  |        ❌      |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|         clear        |       ❌      |     ❌  |        ❌      |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|        remove        |       ❌      |     ❌  |        ❌      |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|       removeAll      |       ❗️       |     ❌   |        ❗️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|       retainAll      |       ❗️       |     ❌  |        ❗️        |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|      replaceAll      |       ❌      |     ❌  |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|          set         |       ❌      |     ❌  |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|         sort         |       ✔️       |     ❌   |        ✔️      |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|  remove on iterator  |       ❌      |     ❌  |        ❌      |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
| set on list-iterator |       ❌      |     ❌  |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
  1. ✔️ significa que el método es compatible
  2. ❌ significa que llamar a este método arrojará una UnsupportedOperationException
  3. ❗️ significa que el método es compatible solo si los argumentos del método no causan una mutación, por ejemplo, Collections.singletonList(“foo”).retainAll(“foo”) está bien, pero Collections.singletonList(“foo”).retainAll(“bar” ) lanza una UnsupportedOperationException

Más sobre Colecciones::singletonList vs. Lista de

Arrays.asList(1, 2, 3);

A de tamaño fijo Lista se creará:

public static void main(String[] args) {
        List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5);
        asList.add(6);    // java.lang.UnsupportedOperationException
        asList.remove(0); // java.lang.UnsupportedOperationException
        asList.set(0, 0); // allowed
}

Lista.de(1, 2, 3);

A Inmutable (Java 9)/No modificable (Java 11) Lista se creará:

public static void main(String[] args) {
    List<Integer> listOf = List.of(1, 2, 3, 4, 5);
    listOf.add(6);    // java.lang.UnsupportedOperationException
    listOf.remove(0); // java.lang.UnsupportedOperationException
    listOf.set(0, 0); // java.lang.UnsupportedOperationException
}

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad