Java Inmutable: Listas y Otras Colecciones

Listas

doSomething ()

   public static final,  Lista  UNSAFE_ZONES = Arrays.asList (
"África / El Cairo"
"África / Johannesburg"
"América / Anchorage"
...);

displayZones (UNSAFE_ZONES);

un método llamado displayZones (zonas Lista ) suena bastante seguro y probablemente no va a cambiar el contenido de la lista que se pasa . Pero a menos que usted cava a ese método con mucho cuidado, no se puede saber a ciencia cierta. Incluso si displayZones () es muy sencillo y seguro hoy, alguien podría utilizarla para envolver la lógica de terceros mañana, o hacer pasar sus UNSAFE_ZONES a otro método que cambia.

Tal vez todo funciona perfectamente, pero usted no duerme bien por la noche porque alguien podría, en cualquier momento, de forma deliberada o accidentalmente cambiar su lista. Tal vez ya está sucediendo en alguna parte, pero es causado por una condición de datos tan raro que usted no ha notado aún. Tal vez has dormido bien, pero hacer el seguimiento de todos los lugares que todo se podría modificar en su aplicación utiliza valioso pensamiento-espacio, le distraiga de los problemas más interesantes.

Zonas horarias no cambian muy a menudo. Esta lista probablemente sólo necesita ser actualizado una vez o dos veces al año. Si realiza comunicados con más frecuencia que eso, no hay ninguna razón por la que una lista como esta tiene que cambiar * nunca * excepto en tiempo de compilación, o tal vez cuando se lee desde un archivo de inicio de la aplicación. Cualquier intento por parte de su programa para cambiar sobre la marcha es un error. Así que lo convierten inmutable.

Aquí es una lista inmutable en Java 5 o posterior.

lista inmutable

   public static final,  Lista  TIME_ZONES = /> 
"África / El Cairo" ,
"África / Johannesburg"
"América / Anchorage"
...)) ;

gente siempre que aparezca la concurrencia con relación a las estructuras de datos inmutables, y la inmutabilidad es un regalo del cielo con respecto a la concurrencia. Puede pasar objetos inmutables y colecciones libremente entre cualquier número de hilos sin ningún bloqueo, la sincronización, copias de defensa, o la contención, que es una gran victoria tanto en términos de rendimiento y simplicidad. Pero a nivel del día a día, incluso con un solo hilo, el gran beneficio para este estilo de codificación es que no se preguntan si algo cambió su colección, ya que no es sólo posible.

Imagínese ahora que usted es el autor de displayZones () y que desea comunicar a las personas que utilizan su API que displayZones () nunca van a modificar la lista que se envía. Una forma de hacer esto es escribir un comentario en el JavaDoc como, «Yo nunca prometo que modificar su lista dentro displayZones ().» Para que esto sea efectivo, la gente tiene que 1. leer el JavaDoc y 2. Puedes creer. Si escribiera eso, ¿me creerías? Diablos, yo no me creo a mí mismo si yo lo escribí el mes pasado!

¿No sería agradable si el compilador lanzaría una advertencia de grasa bueno si alguien alguna vez actualizado displayZones () para modificar la lista que era enviado? Desde TIME_ZONES es una lista y displayZones () siempre se mostrará con el fin ordenado, puede declarar que tome una Iterable lugar de una lista:

   public void  displayZones (zonas Iterable ) {...  

Desde Iterable proporciona sólo sólo lectura métodos para recorrer en orden, la persona que llama sabe que incluso si te pasan una lista modificable, que no tiene que preocuparse por que cambiarlo, porque no se puede. No hay copias de defensa, no se preocupe. Pueden pasar cualquier colección, mutable o inmutable y no importará.

Todavía hay un beneficio para el paso de una colección inmutable. Si alguna vez cambia displayZones tomar un mutable Lista y la persona que llama ya está pasando un mutable Lista , no van a conseguir una advertencia del compilador. ¿No se te sorprendas cuando su lista se ha modificado! Inmutabilidad aquí futuro-las pruebas de código de la persona que llama. Si la persona que llama está pasando a una lista mutable, aunque, tal vez significa que no les importa si se modifica? En cualquier caso, el uso innecesario de datos mutable es una trampa peligrosa.

Otras Colecciones

<> s). Si alguien sabe una mejor manera breve / para hacer esto, por favor deje un comentario:

Inmutable Set

   static final  Establecer  validModes = Collections.unmodifiableSet (
nueva HashSet <> (Arrays.asList (MODE_PREADD, MODE_ADD,
MODE_PREUPDATE, MODE_UPDATE)) );

EnumSet se prefiere para las enumeraciones, ya que se ejecuta más rápido y tiene una sintaxis más breve. EnumSets están ordenados de acuerdo a su «orden natural», que es el orden en que se declaran las constantes de enumeración.

   static final  privada Set  ; validModes = Collections.unmodifiableSet (
EnumSet.of (Mode.PREADD, Mode.ADD, Mode.PREUPDATE, Mode.UPDATE));

Si está utilizando todos los valores de una enumeración en orden:

   static final  privada Set  validModes = Collections.unmodifiableSet (
EnumSet.allOf (Modo . clase));

Inmutable Map

   static final  privada Mapa  shortNameHash ; 

{Mapa m = nueva HashMap <> () ;
m.put (SERVER_NAME_DEMO, "demo" );
m.put (SERVER_NAME_UAT, "UAT" );
m.put (SERVER_NAME_INTEGRATION, "integración" );
m.put (SERVER_NAME_DEV, "dev" );
shortNameHash = Collections.unmodifiableMap (m);
}

Es crítico en el ejemplo que el mapa Mapa temporal m estar en el ámbito dentro de un bloque dedicado de forma que pase fuera de alcance y no se puede acceder por cualquier cosa después de crear la versión inmutable de la misma. Mapa m permanece para siempre mutable, y un cierre léxico (bloque) es la forma más sencilla de mantener ningún tipo de código de acceso de usuario de mantener una referencia directa a la misma.

conversión de tipos

   public enum  implementos class="keyword">  
DropDownItemInterface {...
público static final Lista ddiVals =
Collections.unmodifiableList (Arrays.asList (
valores (DropDownItemInterface []) ()));

Si intenta colar la lista resultante en su lugar, usted verá por qué me he molestado en señalar esto (y por qué tantas personas prefieren lenguajes dinámicos).

Efectividad

getShortName (Map m) , no hay manera eficaz de decir la persona que llama que este método no puede modificar el mapa se le pasa. Google Guava queda corta también en este caso debido a que su estructura de datos ImmutableMap hereda de mapa en lugar de al revés. Esto tiene que ser fijado en el nivel de la API de Java, o de lo contrario, la gente necesita para iniciar la importación de algunos nueva API de colecciones en vez de java.util.

Scala y Clojure ambos hacen todas sus colecciones inmutable por defecto. La versión mutable de cada tipo de colección es una subclase de la inmutable. En cualquier idioma, se podría decir getShortName (ImmutableMap m) (o similar), y tiene los beneficios que he descrito con Iterable. Java podría hacer esto también, y me siento muy fuertemente que deberían.

La razón por la Scala y Clojure colecciones pueden ser inmutables por defecto es que se implementan para permitir copias muy ligeros para hacer muy rápidamente. Las colecciones inmutables en idiomas todavía han add () y put () los métodos que contienen (o equivalente). Ellos sólo devuelven una colección totalmente nueva que incluye la modificación de la anterior. En una colección de hash de tabla basada, sólo el depósito de hash que se cambia aún necesita ser copiado a la nueva colección. Los otros cubos se pueden compartir porque la colección es inmutable!

Java podría permitir que el mismo tipo de copias rápidas y poco profundas de las colecciones, pero tiene la bola y una cadena de 15 años de edad añadir () y put () métodos que devuelven un valor booleano en lugar de la colección subyacente. Debido a que este contamina el espacio de nombres para esos métodos, nuevos nombres de los métodos (como append () y anteponer () ) tendrían que hacerse para todas las operaciones de modificación para que pudieran regresar una copia inmutable modificada de la colección original. Los viejos métodos podrían ser obsoletos con el tiempo. Esto podría llevar a cierta confusión a corto plazo, con gente que se pregunta por qué su colección inmutable no se ha cambiado por un append () llamada, pero yo personalmente creo que valdría la pena en el largo plazo.

A veces se necesita estructuras de datos mutables y por todos los medios, se utilicen. Pero cuando no lo hacen, prefieren inmutabilidad y usted dormirá mejor, piensan con más claridad, y escribir código más robusto.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *