Que fait Collections.unmodifiableSet () en Java?

Je peux voir que Collections.unmodifiableSet renvoie une vue non modifiable de l’ensemble donné, mais je ne comprends pas pourquoi nous ne pouvons pas simplement utiliser le modificateur final pour accomplir cela.

Dans ma compréhension, final déclare une constante: quelque chose qui ne peut pas être modifié. Ainsi, si un ensemble est déclaré en tant que constante, il ne peut pas être modifié: rien ne peut être supprimé de l’ensemble et rien ne peut être ajouté.

Pourquoi avons-nous besoin de Collections.unmodifiableSet ?

final déclare une référence d’object qui ne peut pas être modifiée, par exemple

 private final Foo something = new Foo(); 

crée un nouveau Foo et place la référence dans something . Par la suite, il est impossible de modifier something pour pointer vers une instance différente de Foo .

Cela n’empêche pas la modification de l’état interne de l’object. Je peux toujours appeler toutes les méthodes disponibles sur Foo sont accessibles au périmètre concerné. Si une ou plusieurs de ces méthodes modifient l’état interne de cet object, final n’empêchera pas cela.

À ce titre, les éléments suivants:

 private final Set fixed = new HashSet(); 

ne crée pas un Set qui ne puisse pas être ajouté ou modifié; cela signifie simplement que fixed ne fera jamais référence à cette instance.

En revanche, en faisant:

 private Set fixed = Collections.unmodifiableSet( new HashSet() ); 

crée une instance d’un Set qui fixed.add() si l’on tente d’appeler fixed.add() ou fixed.remove() , par exemple: l’object lui-même protégera son état interne et l’empêchera d’être modifié.

Par souci d’exhaustivité:

 private final Set fixed = Collections.unmodifiableSet( new HashSet() ); 

crée une instance d’un Set qui ne permet pas la modification de son état interne, mais signifie également que « fixed pointe uniquement sur une instance de cet ensemble.

La raison pour laquelle final peut être utilisé pour créer des constantes de primitives est basée sur le fait que la valeur ne peut pas être modifiée. Rappelez-vous que la fixed ci-dessus n’était qu’une référence – une variable contenant une adresse non modifiable. Eh bien, pour les primitives, par exemple

 private final int ANSWER = 42; 

la valeur de ANSWER est celle 42. Puisque la ANSWER ne peut pas être modifiée, elle n’aura jamais que la valeur 42.

Voici un exemple qui brouille toutes les lignes:

 private final Ssortingng QUESTION = "The ultimate question"; 

Selon les règles ci-dessus, QUESTION contient l’adresse d’une instance de Ssortingng qui représente “la question ultime” et cette adresse ne peut pas être modifiée. Ce qu’il faut retenir ici, c’est que Ssortingng lui-même est immuable – vous ne pouvez rien faire avec une instance de Ssortingng qui le modifie, et toute opération qui le ferait autrement (comme le replace , la subssortingngsubssortingng , etc.) renvoie des références entièrement différentes. instances de Ssortingng .

final garantit uniquement que la référence à l’object représenté par la variable ne peut pas être modifiée; il ne fait rien pour l’instance de l’object et sa mutabilité.

final Set s = new Set(); garantit simplement que vous ne pouvez pas faire s = new Set(); encore. Cela ne rend pas le jeu non modifiable, mais si vous ne pouviez rien y append pour commencer. Donc, pour que ce soit vraiment clair, final n’affecte que la variable référence, pas l’object sur lequel la référence pointe.

Je peux faire ce qui suit:

 final List l = new ArrayList(); l.add("hello"); l.add("world"); l.remove(0); 

mais je ne peux pas faire ça.

 l = new ArrayList(); 

encore une fois à cause de la final je ne peux pas modifier le sens de la variable l.

vous devez effectuer l’une des trois opérations suivantes pour sécuriser un thread de conteneur Collection.

 java.util.Collections.syncronizedXXX(); 

ou

 java.util.Collections.unmodifiableXXX(); 

ou utilisez l’un des conteneurs appropriés du java.util.concurrency.* package .

si j’avais un object Person et si j’ai fait une Person final Person p = new Person("me"); cela signifie que je ne peux pas réaffecter p pour qu’il pointe vers un autre object Person . Je peux toujours faire p.setFirstName("you");

Ce qui confond la situation est que

 final int PI = 3.14; final Ssortingng greeting = "Hello World!"; 

ressemblent à const en C ++, alors que les objects qu’ils désignent sont immuables / non modifiables par nature. Les conteneurs ou les objects utilisant des méthodes de mutateur pouvant modifier l’état interne de l’object ne sont pas const mais la référence à ces objects est final et ne peut pas être réaffectée pour référencer un autre object.

final n’est pas (style C ++) const . Contrairement à C ++, Java n’a pas de méthodes const ou quoi que ce soit d’autre, et les méthodes qui peuvent changer l’object peuvent être appelées via une référence final .

Collections.unmodifiable* est un wrapper qui applique (au moment de l’exécution uniquement, pas au moment de la compilation) la lecture seule de la collection concernée.

Collections.unmodifiableSet(Set) créera un wrapper sur le jeu d’origine. Cet ensemble de wrapper ne peut pas être modifié. mais encore le jeu original peut être modifié.

Exemple:

  Set actualSet=new HashSet(); //Creating set 

Ajout de quelques éléments

 actualSet.add("aaa"); actualSet.add("bbb"); 

Impression d’éléments ajoutés

 System.out.println(actualSet); //[aaa, bbb] 

Placez le actualSet dans un ensemble non modifiable et atsortingbuez-le à une nouvelle référence ( wrapperSet ).

 Set wrapperSet=Collections.unmodifiableSet(orginalSet); 

Imprimez le wrapperSet. donc il aura des valeurs actualSet

 System.out.println(wrapperSet); //[aaa, bbb] 

Essayons de supprimer / append un élément sur wrapperSet .

 wrapperSet.remove("aaa"); //UnSupportedOperationException 

Ajouter un élément de plus dans actualSet

  actualSet .add("ccc"); 

Imprimer actualSet et wrapperSet . les deux valeurs sont identiques. donc, si vous ajoutez / supprimez des éléments sur le jeu réel, les modifications seront également répercutées sur le jeu de wrappers.

  System.out.println(actualSet); //[aaa, ccc, bbb] System.out.println(wrapperSet); // [aaa, ccc, bbb] 

Usage:

Collections.unmodifiableSet(Set) est utilisé pour empêcher la modification de la méthode d’accesseur de Set pour tout object. disons

 public class Department{ private Set users=new HashSet(); public Set getUsers(){ return Collections.unmodifiableSet(users); } } 

Résumez ce que nous pouvons faire et ne pouvons pas:

Préparation:

 private Set words = new HashSet<>(Arrays.asList("existing word")); 

Final par référence

 private final Set words = new HashSet<>(); 

peut :

 words.add("new word"); 

ne peut pas :

 words = new HashSet<>(); //compilation error 

Final par référence et non modifiable par collection.

private final Set words = Collections.unmodifiableSet (mots);

peut :

 Ssortingng word = words.iterator().next(); 

ne peut pas :

 words = new HashSet<>(); // compilation error words.add("new word"); // runtime error UnsupportedOperationException 

Final par référence et non modifiable par collection mais mutuel comme object de collection.

Mais si vous avez la collection avec des objects mutuels , vous pouvez CHANGER l’état intérieur de cet object.

  class A { public int a; //mutable field. I can change it after initialization public A(int a) {this.a = a;} } private final Set set = Collections.unmodifiableSet(Arrays.asList(new A(25))); 

Toujours pas

 set = new HashSet<>(); // compilation error set.add(new A(777)); // runtime error UnsupportedOperationException 

Mais peut

  A custom = words.iterator().next(); //here custom.a = 25; custom.a = 777; //here first element of **final, unmodifible** collection //was changed from 25 to 777