Colecciones Inmutables de Java

De la documentación de Java 1.6 Collection Framework :

Las colecciones que no admiten ninguna operación de modificación (como add , remove y clear ) se denominan no modificables . […] Las colecciones que, además, garantizan que ningún cambio en el objeto Colección será visible alguna vez se denominan inmutables .

El segundo criterio me confunde un poco. Dado que la primera colección no se puede modificar, y suponiendo que la referencia de la colección original ha sido eliminada, ¿cuáles son los cambios a los que se hace referencia en la segunda línea? ¿Se está refiriendo a los cambios en los elementos contenidos en la colección, es decir, el estado de los elementos?

Segunda pregunta:
Para que una colección sea inmutable, ¿cómo se hace para proporcionar las garantías adicionales especificadas? Si el estado de un elemento en la colección se actualiza mediante un hilo, ¿es suficiente para la inmutabilidad que esas actualizaciones en el estado no sean visibles en el hilo que contiene la colección inmutable?

Para que una colección sea inmutable, ¿cómo se hace para proporcionar las garantías adicionales especificadas?

Las colecciones no modificables generalmente son vistas de solo lectura (envoltorios) de otras colecciones. No puede agregarlos, eliminarlos o borrarlos, pero la colección subyacente puede cambiar.

Las colecciones inmutables no se pueden cambiar en absoluto, no envuelven otra colección, tienen sus propios elementos.

Aquí hay una cita de ImmutableList de guava

A diferencia de Collections.unmodifiableList(java.util.List) , que es una vista de una colección separada que aún puede cambiar, una instancia de ImmutableList contiene sus propios datos privados y nunca cambiará.

Entonces, básicamente, para obtener una colección inmutable de una mutable, debe copiar sus elementos a la nueva colección y no permitir todas las operaciones.

La diferencia es que no puede tener una referencia a una colección inmutable que permite cambios. Las colecciones no modificables no se pueden modificar a través de esa referencia , pero algunos otros objetos pueden señalar los mismos datos a través de los cuales se pueden modificar.

p.ej

 List strings = new ArrayList(); List unmodifiable = Collections.unmodifiableList(strings); unmodifiable.add("New string"); // will fail at runtime strings.add("Aha!"); // will succeed System.out.println(unmodifiable); 
 Collection c1 = new ArrayList(); c1.add("foo"); Collection c2 = Collections.unmodifiableList(c1); 

c1 es mutable (es decir, no modificable ni inmutable ).
c2 no se puede modificar : no se puede cambiar solo, pero si más adelante cambio c1 , ese cambio será visible en c2 .

Esto se debe a que c2 es simplemente una envoltura alrededor de c1 y no es realmente una copia independiente. Guava proporciona la interfaz ImmutableList y algunas implementaciones. Esos trabajos realmente crean una copia de la entrada (a menos que la entrada sea una colección inmutable por sí misma).

En cuanto a tu segunda pregunta:

La mutabilidad / inmutabilidad de una colección no depende de la mutabilidad / inmutabilidad de los objetos contenidos en ella. La modificación de un objeto contenido en una colección no cuenta como una “modificación de la colección” para esta descripción. Por supuesto, si necesita una colección inmutable, generalmente también desea que contenga objetos inmutables.

Ahora java 9 tiene métodos de fábrica para lista inmutable, conjunto, mapa y entrada de mapa.

En Java SE 8 y versiones anteriores, podemos usar los métodos de utilidad de la clase Collections como unmodifiableXXX para crear objetos de colección inmutable.

Sin embargo, estos métodos Collections.unmodifiableXXX son muy tediosos y de enfoque detallado. Para superar esas deficiencias, Oracle corp ha agregado un par de métodos de utilidad a las interfaces List, Set y Map.

Ahora en java 9: ​​- Las interfaces List y Set tienen métodos “of ()” para crear una lista inmutable vacía o sin vacíos o establecer objetos como se muestra a continuación:

Ejemplo de lista vacía

 List immutableList = List.of(); 

Ejemplo de lista no vacía

 List immutableList = List.of("one","two","three"); 

Creo que el punto aquí es que incluso si una colección es Inmodificable, eso no asegura que no pueda cambiar. Tomemos, por ejemplo, una colección que expulsa elementos si son demasiado viejos. Inmodificable solo significa que el objeto que contiene la referencia no puede cambiarlo, no es que no pueda cambiar. Un verdadero ejemplo de esto es el método Collections.unmodifiableList . Devuelve una vista no modificable de una lista. La referencia de la Lista que se pasó a este método todavía es modificable y, por lo tanto, la lista puede ser modificada por cualquier titular de la referencia que se aprobó. Esto puede dar como resultado ConcurrentModificationExceptions y otras cosas malas.

Inmutable, significa que de ninguna manera se puede cambiar la colección.

Segunda pregunta: una colección inmutable no significa que los objetos contenidos en la colección no cambiarán, solo que la colección no cambiará en el número y la composición de los objetos que contiene. En otras palabras, la lista de referencias de la colección no cambiará. Eso no significa que las partes internas del objeto al que se hace referencia no puedan cambiar.

Pure4J es compatible con lo que buscas, de dos maneras.

Primero, proporciona una anotación @ImmutableValue , para que pueda anotar una clase y decir que es inmutable. Existe un complemento maven que le permite verificar que su código sea realmente inmutable (uso de final versión final etc.).

En segundo lugar, proporciona las colecciones persistentes de Clojure (con generics añadidos) y garantiza que los elementos añadidos a las colecciones sean inmutables. El rendimiento de estos es aparentemente bastante bueno. Las colecciones son inmutables, pero implementan interfaces de colecciones java (y generics) para su inspección. La mutación devuelve nuevas colecciones.

Descargo de responsabilidad: soy el desarrollador de este