Ci sono un paio di casi in cui preferiresti utilizzare mappe, elenchi, set o altri tipi di raccolte immutabili.
Il primo e probabilmente il più importante caso d'uso è ogni volta che si restituisce un risultato di una query o un calcolo che restituisce un insieme (o elenco o mappa) di risultati, è preferibile utilizzare strutture di dati immutabili.
In questo caso, preferisco di gran lunga restituire versioni immutabili di queste in quanto ciò riflette l'immutabilità fattuale di un set di risultati di un calcolo molto più chiaramente - indipendentemente da ciò che fai con i dati in seguito, l'insieme di risultati che hai ricevuto dalla tua query non dovrebbe modificare.
Il secondo caso d'uso comune è quando è necessario fornire un argomento come input per un metodo o un servizio. A meno che non ti aspetti che la raccolta di input venga modificata dal servizio o dal metodo (che di solito è una cattiva idea di design), passare in una raccolta immutabile invece di quella mutabile potrebbe essere la scelta ragionevole e sicura in molti casi.
Lo considero una convenzione "pass by value" .
Più in generale - è una pratica sensata utilizzare una struttura di dati immutabile ogni volta che i dati attraversano i confini del modulo o del servizio. Questo rende molto più facile ragionare sulle differenze tra input / output (immutabili) e stato interno mutabile.
Come effetto collaterale molto vantaggioso di ciò vi è una maggiore sicurezza e sicurezza dei thread dei moduli / servizi e garantisce una separazione più chiara delle preoccupazioni.
Un'altra buona ragione per usare i Collections.empty*()
metodi è la loro notevole mancanza di verbosità. Nell'era pre-Java7, se avevi una collezione generica, dovevi spargere annotazioni di tipo generico ovunque.
Basta confrontare queste due dichiarazioni:
Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();
contro:
Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();
Quest'ultimo vince chiaramente la leggibilità in due modi importanti:
- Nella prima dichiarazione, l'intera istanza di una mappa vuota è sepolta nel rumore delle dichiarazioni di tipo generico, rendendo una dichiarazione essenzialmente banale molto più criptica di quanto debba essere.
- Oltre alla notevole mancanza di annotazioni di tipo generico sul lato destro, la seconda versione afferma chiaramente che la mappa è inizializzata su una mappa vuota. Inoltre, sapendo che questo metodo restituisce una mappa immutabile, ora è più facile per me trovare dove
fooBarMap
viene assegnato un altro valore non vuoto semplicemente cercando /fooBarMap =/
.