Mierzenie się z kolekcjami i poprawnym ich wykorzystaniem jest problematyczne dla początkujących programistów. Jak często widzieliście w jakimś kodzie fragment typu:
Korzystanie z immutable collections wymusza tworzenie kopii kolekcji! Gdybyś udostępnił własną kolekcję w postaci niemutowalnej to nikt nie miałby prawa nic namieszać.
Można również wykorzystać jakąś z bibliotek jak np. Guava, która dostarcza zestaw typów immutable, którymi można się posługiwać zamiast typowych kolekcji z API języka.
Ja stosuję 3 proste zasady:
cart.getProducts().add(product);
Sam pisałem niegdyś takie brzydkie rzeczy. W czasie, w którym wyrabiałem sobie moje skromne doświadczenie wypracowałem sobie jednak pewne zasady jak postępować z kolekcjami. Ktoś mógłby się ze mną spierać - nawet podając sensowne argumenty ale w mojej pracy trzymanie się tych nawyków sprawdza się i na razie się ich trzymam.W czym problem?
Przedstawiony wyżej fragment kodu to wyraźne złamanie zasady enkapsulacji. Skoro obiekt udostępnia swoje wnętrze (w typ przypadku jakąś kolekcję) i można z tym robić wszystko co się nam spodoba to po co te wszystkie modyfikatory dostępu i po co w ogóle taki obiekt? Skoro obiekt, który posiada jako swoją właściwość (property) jakąś listę i udostępnia ją tak po prostu na zewnątrz to może okazać się, że biedny obiekcik jest nieświadomy, że ktoś mu grzebie w brzuchu 😨.Co począć?
Immutable collections! Coś co można by powiedzieć, że istnieje w Java od wieków bo od wersji 1.2, jednak jest to rzecz nieco ukryta przed niedoświadczonymi programistami. Kolekcja niemutowalna to taka, która co prawda posiada dane i zapewnia do nich dostęp ale nie pozwala ich dodawać, ani usuwać. Podczas próby wykonania takiej operacji jest rzucany wyjątekUnsupportedOperationException
. Jak tworzyć takie kolekcje? W Java od 1.2 do 1.8 wystarczy skorzystać z klasy narzędziowej java.util.Collections
i jej metod statycznych unmodifiable...
. Sposób użycia:List<String> strings;
List<String> unmodifiableStrings = Collections.unmodifiableList(strings);
No i co ja z tego mam?
Wyobraź sobie sytuację, że piszesz sobie aplikację na zaliczenie ze swoim kolegą Ryśkiem. Napisałeś piękną klasę, przetestowaną i elegancką. Okazuje się jednak, że aplikacja działa jakoś dziwnie. Brakuje jakichś danych, a czasem są w złej kolejności. Spojrzałeś w kod Ryśka. Okazało się, że potrzebował wpisów z listy, znajdującej się w Twojej klasie i nie zrobił własnej kopii tylko operował na Twojej liście.Korzystanie z immutable collections wymusza tworzenie kopii kolekcji! Gdybyś udostępnił własną kolekcję w postaci niemutowalnej to nikt nie miałby prawa nic namieszać.
No ale to tyle dodatkowego kodu...
No ejj... wcale nie tyle. tylko kilka znaków w linii więcej. Niestety rzeczywistość javova tak w tej chwili wygląda, że wielu udogodnień brakuje w samym języku a dostępne są zazwyczaj w postaci rozrastającego się ciągle API. W innych nowoczesnych językach takie struktury są zapewniane w inny sposób. Np. w pythonie można myśleć o krotce (tuple) jako o liście niemodyfikowalnej. Język Kotlin z kolei zapewnia, że każda kolekcja jest domyślnie immutable o ile programista jawnie nie określi mutowalnego typu kolekcji.Można również wykorzystać jakąś z bibliotek jak np. Guava, która dostarcza zestaw typów immutable, którymi można się posługiwać zamiast typowych kolekcji z API języka.
To kiedy stosować jaką kolekcję?
Odpowiedź jest prosta. Jeśli to tylko możliwe to zawsze stosuj kolekcje niemutowalne!Ja stosuję 3 proste zasady:
- Każdy getter zawsze zwraca kolekcję immutable
- Przy przekazywaniu kolekcji do metody innego obiektu przekazuję kolekcję immutable
- Przy otrzymywaniu kolekcji jako parametr zawsze kopiuję kolekcję. Zabezpieczam się przed sytuacją gdy ktoś przekazał właśnie kolekcję immutable, a zarazem nie psuję mu życia jeśli tego nie zrobił.
Oczywiste rzeczy także warto pisać, to co dla osób siedzących w temacie jest oczywiste, nie dla każdego musi takie być;) Ja wdrażam się w ten temat, dużo czytam. Także stronka https://ermlab.com i ich blog są bardzo pomocne.
OdpowiedzUsuń