java collections java-9

java - Map.of() vs. Collections.emptyMap()



java-9 (2)

¿Hay alguna diferencia entre Map.of() y Collections.emptyMap() , entre List.of() y Collections.emptyList() y entre Set.of() y Collections.emptySet() ?


No. En términos de su firma, ambos métodos devuelven el tipo inmutable de List / Map / Set . Los Javadocs para ambos cuando se comparan indican lo mismo:

Collections.emptyMap()

Devuelve un mapa vacío (inmutable). Este mapa es serializable.

Map.of()

Devuelve un mapa inmutable que contiene cero asignaciones

Sí. en términos de su implementación, por ejemplo:

Collections.emptyMap ()

public static final Map EMPTY_MAP = new EmptyMap<>();

devuelve un Map tipo sin Map mientras que, por otro lado

Mapa de()

private static final Map0<?,?> INSTANCE = new Map0<>();

devuelve un tipo Map0<?,?> que se introduce en Java 9 para el uso interno y la implementación de los métodos de fábrica estáticos. que establece que las instancias de Map creadas por estos métodos tienen las siguientes características:

  • Son estructuralmente inmutables . Las claves y los valores no pueden agregarse, eliminarse ni actualizarse. Llamar a cualquier método de mutador siempre provocará que se genere UnsupportedOperationException. Sin embargo, si las claves o valores contenidos son ellos mismos mutables, esto puede hacer que el Mapa se comporte de manera incoherente o que su contenido parezca cambiar.

  • No permiten claves y valores nulos. Los intentos de crearlos con claves nulas o valores dan como resultado NullPointerException .

  • Se pueden serializar si todas las claves y valores son serializables.

  • Rechazan claves duplicadas en el momento de la creación. Las claves duplicadas transferidas a un método de fábrica estático dan como resultado IllegalArgumentException .

  • El orden de iteración de las asignaciones no está especificado y está sujeto a cambios.

  • Están basados ​​en valores. Las personas que llaman no deben hacer suposiciones sobre la identidad de las instancias devueltas. Las fábricas son libres de crear nuevas instancias o reutilizar las existentes. Por lo tanto, las operaciones sensibles a la identidad en estas instancias (igualdad de referencia (==), código hash de identidad y sincronización) no son confiables y deben evitarse.

  • Se serializan como se especifica en la página de formulario serializado.

Nota : he compartido solo la muestra para Map , aunque lo mismo se aplica a Set and List y a los límites de los métodos estáticos de fábrica.


, incluso hay diferencias conductuales y no solo técnicas entre las colecciones devueltas por los métodos de fábrica emptyXyz en la clase Collections y los nuevos métodos of fábrica introducidos en las interfaces ( Map , List , Set ) con JDK 9, si se invocan con sin argumentos.

La diferencia relevante es que las colecciones devueltas por el nuevo método of fábrica no permiten claves y valores null (como se señala en la documentación de la API en las interfaces Lista , Conjunto y Mapa ). Esto puede parecer irrelivante para las colecciones vacías, pero incluso si no está claramente documentado, incluso los métodos de acceso en las nuevas implementaciones de la colección verifican los valores nulos.

Algunos ejemplos de las diferencias:

Collections.emptyList().contains(null) List.of().contains(null) Collections.emptyList().contains(null) devolverá false, mientras que List.of().contains(null) arrojará una NullPointerException .

Collection.emptyMap().getOrDefault(null, V) devolverá V , mientras que Map.of().getOrDefault(null, V) arrojará una NullPointerException .

Tal como se implementa actualmente en Oracle JDK 9, al menos los siguientes métodos en las colecciones devueltas por los nuevos métodos de fábrica arrojarán NullPointerException , pero se comportarán "sanamente" (como en cómo las clases de colección se diseñaron y especificaron originalmente para admitir claves y valores nulos) ) usando los viejos métodos de fábrica en la clase Collections :

  • List.of().contains(null);
  • Set.of().contains(null);
  • Map.of().containsKey(null);
  • Map.of().containsValue(null);
  • Map.of().getOrDefault(null, <any>);