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:
- 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.
- 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
fooBarMap
se le está asignando otro valor no vacío simplemente buscando /fooBarMap =/
.