Jest kilka przypadków, w których wolisz używać niezmiennych map, list, zestawów lub innych typów kolekcji.
Pierwszym i prawdopodobnie najważniejszym przypadkiem użycia jest to, że zawsze, gdy zwracasz wynik zapytania lub obliczenia, które zwróciłyby zestaw (lub listę lub mapę) wyników, powinieneś preferować użycie niezmiennych struktur danych.
W tym przypadku wolę zwracać ich niezmienne wersje, ponieważ odzwierciedla to faktyczną niezmienność zestawu wyników obliczeń znacznie wyraźniej - bez względu na to, co zrobisz z danymi później, zestaw wyników otrzymanych z zapytania nie powinien zmiana.
Drugim typowym przypadkiem użycia jest podanie argumentu jako danych wejściowych do metody lub usługi. O ile nie spodziewasz się, że kolekcja wejściowa zostanie zmodyfikowana przez usługę lub metodę (co zwykle jest naprawdę złym pomysłem projektowym), przekazanie niezmiennej kolekcji zamiast mutowalnej może być w wielu przypadkach rozsądnym i bezpiecznym wyborem.
Myślę o tym jako o konwencji „przekazywania wartości” .
Mówiąc bardziej ogólnie - rozsądną praktyką jest stosowanie niezmiennych struktur danych, gdy dane przekraczają granice modułów lub usług. To znacznie ułatwia wnioskowanie o różnicach między (niezmiennym) wejściem / wyjściem a zmiennym stanem wewnętrznym.
Bardzo korzystnym efektem ubocznym jest zwiększone bezpieczeństwo i bezpieczeństwo wątków Twoich modułów / usług oraz zapewnia czystsze oddzielenie problemów.
Innym dobrym powodem do używania Collections.empty*()
metod jest ich zauważalny brak słownictwa. W erze przed Java7, jeśli miałeś kolekcję ogólną, musiałeś posypać adnotacjami typu ogólnego w każdym miejscu.
Wystarczy porównać te dwie deklaracje:
Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();
przeciw:
Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();
Ta ostatnia wyraźnie wygrywa pod względem czytelności na dwa ważne sposoby:
- W pierwszej deklaracji cała instancja pustej mapy jest ukryta w szumie deklaracji typu ogólnego, co sprawia, że zasadniczo trywialna deklaracja jest o wiele bardziej tajemnicza, niż powinna.
- Oprócz zauważalnego braku adnotacji typu ogólnego po prawej stronie, druga wersja wyraźnie stwierdza, że mapa jest zainicjowana jako pusta mapa. Ponadto - wiedząc, że ta metoda zwraca niezmienną mapę, teraz łatwiej jest mi znaleźć miejsce, w którym
fooBarMap
jest przypisywana kolejna niepusta wartość, po prostu wyszukując /fooBarMap =/
.