web-dev-qa-db-fra.com

Collection immuable vs non modifiable

De la Vue d'ensemble de la structure de collections :

Les collections qui ne prennent pas en charge les opérations de modification (telles que add, remove et clear) sont appelées non modifiables . Les collections qui ne sont pas non modifiables sont modifiables .

Les collections qui garantissent en outre qu’aucun changement ne sera visible dans l’objet Collection sont appelées immuables . Les collections qui ne sont pas immuables sont mutables .

Je ne peux pas comprendre la distinction.
Quelle est la différence entre non modifiable et immuable ici ?

152
Cratylus

Une collection non modifiable est souvent une enveloppe autour d'une collection modifiable à laquelle un autre code peut toujours avoir accès. Ainsi, bien que vous ne puisse y apporter aucune modification si vous n’avez qu’une référence à la collection non modifiable, vous ne pouvez pas compter sur le contenu qui ne change pas.

Une collection immuable garantit que rien ne peut plus modifier la collection. Si elle encapsule une collection modifiable, elle s'assure qu'aucun autre code n'a accès à cette collection modifiable. Notez que bien qu'aucun code ne puisse modifier les objets vers lesquels la collection contient des références, les objets eux-mêmes peuvent toujours être mutables - la création d'une collection immuable de StringBuilder ne "gèle" pas ces objets.

Fondamentalement, la différence consiste à savoir si un autre code peut modifier la collection derrière votre dos.

192
Jon Skeet

Fondamentalement, unModifiable Collection est une vue. Ainsi, indirectement, elle pourrait tout de même être "modifiée" par une autre référence modifiable. Aussi comme juste ) afficher en lecture seule de la collection annother, Lorsque la collection source change, la collection non modifiable sera toujours présente avec les dernières valeurs.

Cependant, immutable Collection peut être traitée comme une copie en lecture seule d'une autre collection et ne peut pas être modifiée. Dans ce cas, lorsque la collection source est modifiée, la collection immuable ne reflète pas les modifications.

Voici un cas de test pour visualiser cette différence.

@Test
public void testList() {

    List<String> modifiableList = new ArrayList<String>();
    modifiableList.add("a");

    System.out.println("modifiableList:"+modifiableList);
    System.out.println("--");


    //unModifiableList

    assertEquals(1, modifiableList.size());

    List<String> unModifiableList=Collections.unmodifiableList(
                                        modifiableList);

    modifiableList.add("b");

    boolean exceptionThrown=false;
    try {
        unModifiableList.add("b");
        fail("add supported for unModifiableList!!");
    } catch (UnsupportedOperationException e) {
        exceptionThrown=true;
        System.out.println("unModifiableList.add() not supported");
    }
    assertTrue(exceptionThrown);

    System.out.println("modifiableList:"+modifiableList);
    System.out.println("unModifiableList:"+unModifiableList);

    assertEquals(2, modifiableList.size());
    assertEquals(2, unModifiableList.size());
            System.out.println("--");



            //immutableList


    List<String> immutableList=Collections.unmodifiableList(
                            new ArrayList<String>(modifiableList));

    modifiableList.add("c");

    exceptionThrown=false;
    try {
        immutableList.add("c");
        fail("add supported for immutableList!!");
    } catch (UnsupportedOperationException e) {
        exceptionThrown=true;
        System.out.println("immutableList.add() not supported");
    }
    assertTrue(exceptionThrown);


    System.out.println("modifiableList:"+modifiableList);
    System.out.println("unModifiableList:"+unModifiableList);
    System.out.println("immutableList:"+immutableList);
    System.out.println("--");

    assertEquals(3, modifiableList.size());
    assertEquals(3, unModifiableList.size());
    assertEquals(2, immutableList.size());

}

sortie

modifiableList:[a]
--
unModifiableList.add() not supported
modifiableList:[a, b]
unModifiableList:[a, b]
--
immutableList.add() not supported
modifiableList:[a, b, c]
unModifiableList:[a, b, c]
immutableList:[a, b]
--
83
Prashant Bhate

Je pense que la principale différence est que le propriétaire d'une collection mutable peut vouloir donner accès à la collection à un autre code, mais fournir cet accès via une interface qui ne permet pas à l'autre code de modifier la collection (tout en réservant cette possibilité). au code propriétaire). La collection n'est donc pas immuable, mais certains utilisateurs ne sont pas autorisés à modifier la collection.

Le tutoriel d'Oracle de Java Collection Wrapper a ceci à dire (caractères gras ajoutés):

Les emballages non modifiables ont deux utilisations principales, à savoir:

  • Rendre une collection immuable une fois celle-ci construite. Dans ce cas, il est judicieux de ne pas conserver de référence à la collection de supports. Cela garantit absolument l'immuabilité.
  • Pour autoriser certains clients à accéder en lecture seule à vos structures de données. Vous conservez une référence à la collection de supports, mais vous distribuez une référence au wrapper. De cette manière, les clients peuvent regarder mais ne pas modifier, tout en maintenant un accès complet .
11
Michael Burr

Pour citer tutoriels Java ™ :

Contrairement aux wrappers de synchronisation, qui ajoutent des fonctionnalités à la collection encapsulée, les wrappers non modifiables suppriment les fonctionnalités. En particulier, , ils suppriment la possibilité de modifier la collection en interceptant toutes les opérations susceptibles de modifier la collection et en lançant une exception UnsupportedOperationException . Les emballages non modifiables ont deux utilisations principales, à savoir:

  • Rendre une collection immuable une fois celle-ci construite. Dans ce cas, il est judicieux de ne pas conserver de référence à la collection de supports. Cela garantit absolument l'immuabilité.

  • Autoriser certains clients à accéder en lecture seule à vos structures de données. Vous conservez une référence à la collection de supports, mais vous distribuez une référence au wrapper. De cette manière, les clients peuvent regarder sans modifier, tout en maintenant un accès complet.

(c'est moi qui souligne)

Cela résume vraiment le problème.

2
Bharath

Si nous parlons de JDK Unmodifiable* vs goyave Immutable*, en fait, la différence réside également dans les performances . Les collections immuables peuvent être à la fois plus rapides et plus efficaces en termes de mémoire si elles ne sont pas des enveloppes autour de collections régulières (les implémentations de JDK sont des wrappers). citant l'équipe de goyave :

JDK fournit les méthodes Collections.unmodifiableXXX, mais à notre avis, elles peuvent être

<...>

  • inefficace: les structures de données ont encore tout l’argent des collections mutables, y compris les contrôles de modification simultanés, l’espace supplémentaire dans les tables de hachage, etc.
2
Dmide

Comme indiqué ci-dessus, non modifiable n'est pas comme immuable, car une collection non modifiable peut être modifiée si, par exemple, une collection non modifiable a une collection délégante sous-jacente qui est référencée par un autre objet et que cet objet la modifie.

En ce qui concerne immuable, ce n’est même pas bien défini. Cependant, cela signifie généralement que l'objet "ne changera pas", mais que cela doit être défini de manière récursive. Par exemple, je peux définir des classes immuables dont les variables d'instance sont toutes des primitives et dont les méthodes ne contiennent aucun argument et renvoient des primitives. Les méthodes permettent ensuite, de manière récursive, que les variables d'instance soient immuables et que toutes les méthodes contiennent des arguments immuables et renvoyant des valeurs immuables. Les méthodes doivent être garanties pour renvoyer la même valeur au fil du temps.

En supposant que nous puissions le faire, il existe également le concept thread safe. Et vous pourriez être amené à croire que immuable (ou non modifiable dans le temps) implique également un thread-safe.Cependant, ce n'est pas le cas et c'est le point principal que je soulève ici cela n'a pas encore été noté dans d'autres réponses. Je peux construire un objet immuable qui retourne toujours les mêmes résultats sans pour autant être thread-safe. Pour voir cela, supposons que je construise une collection immuable en maintenant des ajouts et des suppressions au fil du temps. Désormais, la collection immuable renvoie ses éléments en examinant la collection interne (qui peut évoluer dans le temps), puis en ajoutant et en supprimant (en interne) les éléments ajoutés ou supprimés après la création de la collection. Clairement, bien que la collection renvoie toujours les mêmes éléments, elle n’est pas thread-safe car elle ne changera jamais de valeur.

Nous pouvons maintenant définir immuable comme des objets thread-safe qui ne changeront jamais. Il existe des directives pour la création de classes immuables menant généralement à de telles classes. Toutefois, gardez à l'esprit qu'il peut exister des moyens de créer des classes immuables nécessitant une attention particulière pour la sécurité des threads, comme décrit dans l'exemple de collection "instantané" ci-dessus.

1
dan b