web-dev-qa-db-fra.com

Quelle est la différence entre Collections.unmodifiableSet () et ImmutableSet of Guava?

JavaDoc de ImmutableSet dit:

Contrairement à Collections.unmodifiableSet, Qui est une vue d'une collection distincte qui peut encore changer, une instance de cette classe contient ses propres données privées et ne changera jamais. Cette classe est pratique pour les ensembles finaux statiques publics ( "ensembles constants") et vous permet également de faire facilement une "copie défensive" d'un ensemble fourni à votre classe par un appelant.

Mais le ImmutableSet stocke toujours la référence des éléments, je n'ai pas pu comprendre la différence avec Collections.unmodifiableSet(). Échantillon:

StringBuffer s=new StringBuffer("a");
ImmutableSet<StringBuffer> set= ImmutableSet.of(s);
s.append("b");//s is "ab", s is still changed here!

Quelqu'un pourrait-il l'expliquer?

44

Considère ceci:

Set<String> x = new HashSet<String>();
x.add("foo");

ImmutableSet<String> guava = ImmutableSet.copyOf(x);
Set<String> builtIn = Collections.unmodifiableSet(x);

x.add("bar");
System.out.println(guava.size()); // Prints 1
System.out.println(builtIn.size()); // Prints 2

En d'autres termes, ImmutableSet est immuable, quelle que soit la collection à partir de laquelle il est potentiellement modifié, car il crée une copie. Collections.unmodifiableSet empêche la modification directe de la collection retournée, mais c'est toujours une vue sur un ensemble de supports potentiellement changeant.

Notez que si vous commencez à changer le contenu des objets référencé par n'importe quel ensemble, tous les paris sont de toute façon désactivés. Ne fais pas ça. En effet, c'est rarement une bonne idée de créer un ensemble en utilisant un type d'élément mutable en premier lieu. (Idem mappe en utilisant un type de clé mutable.)

89
Jon Skeet

Outre la différence de comportement mentionnée par Jon, une différence importante entre ImmutableSet et Set créée par Collections.unmodifiableSet est que ImmutableSet est un type. Vous pouvez en passer un et garder clair que l'ensemble est immuable en utilisant ImmutableSet plutôt que Set dans tout le code. Avec Collections.unmodifiableSet, le type renvoyé est simplement Set... il est donc clair que l'ensemble n'est pas modifiable au point où il est créé, sauf si vous ajoutez Javadoc partout où vous passez ce Set en disant "this l'ensemble n'est pas modifiable ".

21
ColinD

Kevin Bourrillion (développeur principal de Guava) compare les collections immuables/non modifiables dans cette présentation . Bien que la présentation ait deux ans et se concentre sur "Google Collections" (qui est maintenant une sous-partie de la goyave), il s'agit d'une présentation très intéressante . L'API a peut-être changé ici et là (l'API Google Collections était en version bêta à l'époque), mais les concepts derrière Google Collections/Guava sont toujours valides.

Vous pourriez également être intéressé par cette autre SO question ( Quelle est la différence entre Google ImmutableList et Collections.unmodifiableList ()) .

10
Etienne Neveu

Une différence entre les deux non mentionnées dans les autres réponses est que ImmutableSet ne permet pas les valeurs null, comme décrit dans Javadoc

Un ensemble hautes performances immuable avec un ordre d'itération fiable et spécifié par l'utilisateur. Ne permet pas les éléments nuls.

(La même restriction s'applique aux valeurs de toutes les collections immuables de Goyave.)

Par exemple:

ImmutableSet.of(null);
ImmutableSet.builder().add("Hi").add(null); // Fails in the Builder.
ImmutableSet.copyOf(Arrays.asList("Hi", null));

Tous ces éléments échouent au moment de l'exécution. En revanche:

Collections.unmodifiableSet(new HashSet<>(Arrays.asList("Hi", null)));

C'est bon.

3
Andy Turner