Collections.emptyMap () vs new HashMap ()

143

¿Cuáles son algunas de las situaciones en las que puedo usar Collections.emptyMap()? La documentación dice que puedo usar este método si quiero que mi colección sea inmutable.

¿Por qué querría una colección vacía inmutable? ¿Cual es el punto?

Vinoth Kumar CM
fuente
12
1 a la pregunta porque nunca he visto ese método estático antes
Tim Bender
También puede echar un vistazo a las lentes scala google scala lens . EmptyMap y immutableMap se pueden usar para crear objetos, que son inmutables. emptyMap es el punto inicial. Cada vez que se agrega un elemento, el mapa se reemplaza por un mapa que contiene el elemento antiguo y los elementos nuevos. El punto es que los accesos al objeto son seguros.
michael_s
1
Es como Objective-C [NSArray array], devuelve un objeto que, aunque no es utilizable, existe. Entonces puedes jugar con él como un objeto normal y no obtener un error.
Shane Hsu

Respuestas:

144

De Effective Java , artículo # 43 - "Return empty arrays or collections, not null"demuestra devolver una colección vacía y quizás incluso demuestra el uso de estos emptyList(), emptySet()y emptyMap()los métodos de la clase de las Colecciones de obtener una colección vacía que también tiene el beneficio adicional de ser inmutable. Del artículo # 15 "Minimize Mutability" .

De Colecciones-emptySet-Collections-emptyList-Collections

Es un tipo de lenguaje de programación. Esto es para personas que no quieren variables nulas. Entonces, antes de que el conjunto se inicialice, pueden usar el conjunto vacío.

Nota: El siguiente código es solo un ejemplo (cámbielo según su caso de uso):

private Set myset = Collections.emptySet();

void initSet() {
   myset = new HashSet();
}
void deleteSet() {
   myset = Collections.emptySet();
}

Estos métodos ofrecen un par de ventajas:

  1. Son más concisos porque no es necesario que escriba explícitamente el tipo genérico de la colección; generalmente solo se infiere del contexto de la llamada al método.

  2. Son más eficientes porque no se molestan en crear nuevos objetos; simplemente reutilizan un objeto vacío e inmutable existente. Este efecto generalmente es muy leve, pero ocasionalmente (bueno, rara vez) es importante.

Sumit Singh
fuente
15
+1 para la referencia efectiva de Java. Una cuestión: recomendaría la parametrización Sety HashSeten sus ejemplos, ya que el punto principal del emptySet()método y sus amigos (a diferencia de las constantes, Collections.EMPTY_SETetc.) es que juegan muy bien con los genéricos. Además, el uso de una función (tipos sin formato) que ha quedado en desuso desde Java 5 no es una buena ayuda para la enseñanza.
Daniel Pryden
44
No estoy convencido ... ¿No tiene sentido utilizar un en Collectionlugar de nullevitar Exceptionsser arrojado a las siguientes operaciones? Usar una colección inmutable solo resultaría en algún otro tipo de excepción que imagino. Y la asignación nulles ciertamente no menos eficiente que la asignación de una constante inmutable.
fgysin reinstala a Monica
14
@fgysin: si tiene una API donde se espera que los clientes modifiquen la colección, entonces sí, no tiene sentido devolver una colección inmutable. Pero si tiene una API donde devuelve una colección que los clientes no deben modificar y solo deben iterar, entonces devolver una vista a la colección subyacente tiene mucho sentido para asegurarse de que un cliente "malo" no modifique accidentalmente las colecciones de propiedad por ti. Devolver una colección vacía en lugar de nulo significa que su cliente no tiene que hacer una verificación nula antes de usar la colección, lo que aclara el código del cliente.
Jean Hominal
44
public boolean setExists() { return !myset.equals(Collections.emptySet()); }
Assylias
55
En su ejemplo, está verificando explícitamente el conjunto vacío y usándolo como valor centinela, y su clase es mutable. Su pequeño ejemplo utiliza centinelas y mutabilidad, que es exactamente lo que Collections.emptySet () está tratando de evitar.
Marc O'Morain
33

Es, en mi experiencia personal, ciertamente, muy útil en los casos en que una API requiere una colección de parámetros, pero no tiene nada que proporcionar. Por ejemplo, puede tener una API que se parece a esto, y no permite referencias nulas:

public ResultSet executeQuery(String query, Map<String, Object> queryParameters);

Si tiene una consulta que no toma ningún parámetro, sin duda es un poco despilfarrador crear un HashMap, que implica la asignación de una matriz, cuando simplemente puede pasar el 'Mapa vacío', que es efectivamente una constante, la forma en que se implementa en java.util.Collections.

Affe
fuente
22

¿Por qué querría una colección vacía inmutable? ¿Cual es el punto?

Aquí hay dos conceptos diferentes que parecen extraños cuando se ven juntos. Tiene más sentido cuando trata los dos conceptos por separado.

  • En primer lugar, debe preferir usar una colección inmutable en lugar de una colección mutable siempre que sea posible. Los beneficios de la inmuablidad están bien documentados en otros lugares .

  • En segundo lugar, debe preferir usar una colección vacía en lugar de usar null como centinela. Esto está bien descrito aquí . Significa que tendrá un código mucho más limpio y fácil de entender, con menos lugares para esconder errores.

Entonces, cuando tiene un código que requiere un mapa, es mejor pasar un mapa vacío en lugar de un nulo para indicar la ausencia de un mapa. Y la mayoría de las veces cuando usa un mapa, es mejor usar un mapa inmutable. Por eso hay una función conveniente para hacer un mapa vacío inmutable.

Marc O'Morain
fuente
8

Hay un par de casos en los que preferiría usar mapas, listas, conjuntos u otros tipos de colecciones inmutables.

El primer y posiblemente el caso de uso más importante es cuando devuelve un resultado de una consulta o un cálculo que devolvería un conjunto (o lista o mapa) de resultados, debería preferir utilizar estructuras de datos inmutables.

En este caso, prefiero devolver versiones inmutables de estos, ya que esto refleja la inmutabilidad objetiva de un conjunto de resultados de un cálculo mucho más claro: no importa lo que haga con los datos más adelante, el conjunto de resultados que recibió de su consulta no debería cambio.

El segundo caso de uso común es cuando necesita proporcionar un argumento como entrada para un método o servicio. A menos que espere que la colección de entrada sea modificada por el servicio o método (que generalmente es una idea de diseño realmente mala), pasar una colección inmutable en lugar de una mutable podría ser la opción razonable y segura en muchos casos.

Lo considero una convención de "pasar por valor" .

En términos más generales , es una práctica sensata utilizar estructuras de datos inmutables cuando los datos cruzan los límites del módulo o servicio. Esto hace que sea mucho más fácil razonar sobre las diferencias entre la entrada / salida (inmutable) y el estado interno mutable.

Como un efecto secundario muy beneficioso de esto es una mayor seguridad y seguridad de subprocesos de sus módulos / servicios y garantiza una separación más limpia de las preocupaciones.

Otra buena razón para usar Collections.empty*()métodos es su notable falta de verbosidad. En la era anterior a Java7, si tenía una colección genérica, tenía que rociar anotaciones de tipo genérico por todas partes.

Simplemente compare estas dos declaraciones:

Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();

versus:

Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();

Este último claramente gana claramente la legibilidad de dos maneras importantes:

  1. En la primera declaración, toda la creación de instancias de un mapa vacío está enterrada en el ruido de las declaraciones de tipo genérico, lo que hace que una declaración esencialmente trivial sea mucho más críptica de lo que debe ser.
  2. Además de la notable falta de anotaciones de tipo genérico en el lado derecho, la segunda versión establece claramente que el mapa se inicializa en un mapa vacío. Además, sabiendo que este método devuelve un mapa inmutable, ahora es más fácil para mí encontrar dónde fooBarMapse le está asignando otro valor no vacío simplemente buscando /fooBarMap =/.
Roland Tepp
fuente
5

Por un lado, puede salirse con la suya compartiendo referencias. Un new HashMap()etc. requerirá un objeto asignado y posiblemente algunos elementos adicionales para contener los datos, pero solo necesita una copia de una colección vacía inmutable (lista, conjunto, mapa o cualquier otro). Esto lo convierte en una opción obvia cuando un método al que está llamando necesita aceptar un Mapa pero no necesita editarlo.

Sugiero revisar el Java efectivo de Josh Bloch , que enumera algunos atributos muy agradables de objetos inmutables (incluida la seguridad de subprocesos).

Jeff Bowman
fuente
3

Puede ser útil cuando tiene una función que devuelve immutable collectiony, en alguna situación, no hay datos que devolver, por lo que en lugar de regresar null, puede regresaremptyMap()

Facilita tu código y evita NullPointerException

iTech
fuente
3

La mayoría de las veces usamos a constructorpara crear uno nuevo empty map. Pero Collections methodsofrecen un par de ventajas para crear un empty mapusostatic method java.util.Collections.emptyMap()

  1. Son más concisos porque no es necesario que escriba explícitamente el tipo genérico de la colección; generalmente solo se infiere del contexto de la llamada al método.

  2. Son más eficientes porque no se molestan en crear nuevos objetos; simplemente reutilizan un objeto vacío e inmutable existente. Este efecto generalmente es muy leve, pero ocasionalmente (bueno, rara vez) es importante.

subodh
fuente
2

¿Por qué querría una colección vacía inmutable? ¿Cual es el punto?

Por la misma razón que usarías Collections.unmodifiableMap()en algún momento. Desea devolver una instancia de Map que arroje una excepción si el usuario intenta modificarla. Es solo un caso especial: el Mapa vacío.

Ryan Stewart
fuente
1

¿Por qué querría una colección vacía inmutable? ¿Cual es el punto?

Por las mismas razones por las cuales podrías querer objetos inmutables. Principalmente porque puedes dormir seguro por la noche sabiendo que varios hilos pueden acceder a la misma instancia de un objeto y que todos verán los mismos valores. No tener elementos en una colección sigue siendo un valor válido, que desea mantener.

vegemite4me
fuente