Il existe quelques cas où vous préféreriez utiliser des cartes, des listes, des ensembles ou d'autres types de collections immuables.
Le premier cas d'utilisation, et sans doute le plus important, est que chaque fois que vous retournez un résultat d'une requête ou d'un calcul qui renverrait un ensemble (ou une liste ou une carte) de résultats, vous devriez préférer utiliser des structures de données immuables.
Dans ce cas, je préfère de loin renvoyer des versions immuables de ceux-ci car cela reflète l'immuabilité factuelle d'un ensemble de résultats d'un calcul beaucoup plus clairement - peu importe ce que vous faites avec les données plus tard, l'ensemble de résultats que vous avez reçu de votre requête ne devrait pas changement.
Le deuxième cas d'utilisation courant est celui où vous devez fournir un argument en tant qu'entrée d'une méthode ou d'un service. Sauf si vous vous attendez à ce que la collection d'entrée soit modifiée par le service ou la méthode (ce qui est généralement une très mauvaise idée de conception), transmettre une collection immuable au lieu de la collection mutable peut être le choix raisonnable et sûr dans de nombreux cas.
Je pense que c'est une convention «passe par valeur» .
Plus généralement , il est judicieux d'utiliser des structures de données immuables chaque fois que les données franchissent les limites d'un module ou d'un service. Cela rend beaucoup plus facile de raisonner sur les différences entre les entrées / sorties (immuables) et l'état interne mutable.
Un effet secondaire très bénéfique de ceci est une sécurité accrue et la sécurité des threads de vos modules / services et assure une séparation plus nette des problèmes.
Une autre bonne raison d'utiliser les Collections.empty*()
méthodes est leur manque notable de verbosité. Dans l'ère pré-Java7, si vous aviez une collection générique, vous deviez saupoudrer des annotations de type générique partout.
Comparez simplement ces deux déclarations:
Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();
contre:
Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();
Ce dernier gagne clairement en lisibilité de deux manières importantes:
- Dans la première déclaration, toute l'instanciation d'une carte vide est enterrée dans le bruit des déclarations de type générique, ce qui rend une déclaration essentiellement triviale beaucoup plus cryptique qu'elle ne devrait l'être.
- En plus du manque notable d'annotation de type générique sur le côté droit, la deuxième version indique clairement que la carte est initialisée sur une carte vide. De plus, sachant que cette méthode renvoie une carte immuable, il m'est maintenant plus facile de trouver où
fooBarMap
est assignée une autre valeur non vide simplement en recherchant /fooBarMap =/
.