La réponse acceptée por Bozho est correcte. Voici un peu plus d'informations, un exemple de code, et une suggestion d'alternative.
L'unmodifiableList est soutenu par la liste originale
Ce unmodifiableList
méthode dans Collections
La classe utilitaire ne crée pas une nouvelle liste, mais une pseudo-liste. soutenu par par la liste originale. Toute tentative d'ajout ou de suppression effectuée par le biais de l'objet "non modifiable" sera bloquée, et le nom est donc conforme à son objectif. Mais en effet, comme vous l'avez montré, la liste originale peut être modifiée et affecte simultanément notre liste secondaire non-modifiable.
Ceci est expliqué dans la documentation de la classe :
Renvoie une vue non modifiable de la liste spécifiée. Cette méthode permet aux modules de fournir aux utilisateurs un accès en "lecture seule" aux listes internes. Les opérations de requête sur la liste renvoyée "lisent à travers" la liste spécifiée, et les tentatives de modification de la liste renvoyée, que ce soit directement ou via son itérateur, entraînent une UnsupportedOperationException.
Ce quatrième mot est la clé : view
. Le nouvel objet liste n'est pas une nouvelle liste. Il s'agit d'une superposition. Tout comme papier calque ou film de transparence sur un dessin vous empêche de faire des marques sur le dessin, cela ne vous empêche pas d'aller en dessous pour modifier le dessin original.
La morale de l'histoire : N'utilisez pas Collections.unmodifiableList pour faire des copies défensives de listes.
Idem pour Collections.unmodifiableMap
, Collections.unmodifiableSet
et ainsi de suite.
Voici un autre exemple illustrant ce problème.
String dog = "dog";
String cat = "cat";
String bird = "bird";
List< String > originalList = new ArrayList<>( 3 );
originalList.add( dog );
originalList.add( cat );
originalList.add( bird );
List< String > unmodList = Collections.unmodifiableList( originalList );
System.out.println( "unmod before: " + unmodList ); // Yields [dog, cat, bird]
originalList.remove( cat ); // Removing element from original list affects the unmodifiable list?
System.out.println( "unmod after: " + unmodList ); // Yields [dog, bird]
Google Guava
Au lieu de la Collections
pour une programmation défensive, je recommande d'utiliser la classe Google Guava et sa bibliothèque ImmutableCollections l'installation.
Vous pouvez faire une nouvelle liste.
public static final ImmutableList<String> ANIMALS = ImmutableList.of(
dog,
cat,
bird );
Ou vous pouvez faire une copie défensive d'une liste existante. Dans ce cas, vous obtiendrez une nouvelle liste distincte. La suppression de la liste originale no affecter (rétrécir) la liste immuable.
ImmutableList<String> ANIMALS = ImmutableList.copyOf( originalList ); // defensive copy!
Mais n'oubliez pas que si la définition de la collection est distincte, les objets contenus sont partagés par la liste originale et la nouvelle liste immuable. En faisant cette copie défensive, nous ne dupliquons pas l'objet "chien". Un seul objet "chien" reste en mémoire, les deux listes contiennent une référence pointant vers le même chien. Si les propriétés de l'objet "chien" sont modifiées, les deux collections pointent vers le même objet "chien" et les deux collections verront donc la nouvelle valeur de la propriété du chien.