Guava – Kolekcje
Bardzo często używaną przez programistów biblioteką jest Guava – Biblioteka stworzona przez Google. Zawiera wiele mini bibliotek, które w bardzo wielu przypadkach ułatwiają życie.
W ciągu najbliższych kilku tutoriali, skupę się na w miarę dokładnym opisaniu Guavy i pokażę na kilku w miarę prostych przykładach najpopularniejsze elementy tej biblioteki.
Zaczynamy ?
Instalacja
Instalacja jest banalna i wykonywana za pomocą mavena. Dodaj dependency do pom.xml:
1 2 3 4 5 |
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>18.0</version> </dependency> |
Guava Kolekcje
Wszyscy znamy stare dobre
1 |
List<String> list = new ArrayList<String>(); |
Czy można jakoś to uprościć? Okazuje się, że tak !
Guava udostępnia kilka metod statycznych do tworzenia kolekcji
List
1 |
List<String> guavaList = Lists.newArrayList(); |
Wygląda lepiej? Prosty builder, który zgadnie typ w diamondach, utworzy arrayliste.
Można jeszcze fajniej przy okazji utworzyć listę z elementami…
1 |
List<String> guavaList = Lists.newArrayList("element1","element2","element3"); |
Set
Oczywiście to samo możemy zrobić z setem..
1 |
Set<String> guavaSet = Sets.newHashSet("element1","element2","element3"); |
Map
A może mapa?
1 |
Map<Long,String> guavaMap = Maps.newHashMap(); |
Multiset
Guava wprowadza też własne implementacje kolekcji
Multiset to nic innego jak set, który może trzymać wiele tych samych instancji tego samego obiektu. Prawie jak lista. Róznica polega na tym, że lista pozwala na trzymanie duplikatów obiektów, ale jest zawsze w jakiś sposób posortowana. Multiset natomiast pozwala trzymać duplikaty obiektów, ale nie gwarantuje w żaden sposób posortowania.
Użycie jest bardzo proste i nawet dodaje kilka fajnych smaczków 🙂
1 |
Multiset<String> guavaMultiset = HashMultiset.create(); |
Możemy za jednym zamachem dodać np 10 instancji tego samego obiektu:
1 |
guavaMultiset.add("element",10); |
I kilka usunąć…
1 |
guavaMultiset.remove("element",2); |
Szybko policzyć ile jest instancji danego obiektu…
1 |
guavaMultiset.count("element"); |
I szybko zmienić tą ilość na zupełnie inną…
1 |
guavaMultiset.setCount("element",122); |
Multimap
Kolejnym własnym wymysłem Guavy jest multimap.
Multimap to podobnie jak Multiset zbiór elementów, które są czymś pomiędzy mapą, a kolekcją (np listą). Przede wszystkim Muplimap pozwala na duplikaty w kluczach 🙂
Oto kilka przykładów:
1 2 3 4 5 6 7 |
Multimap<String,String> multimap = ArrayListMultimap.create(); multimap.put("Kowalski","Jan"); multimap.put("Kowalski","Piotr"); multimap.put("Kowalski","Andrzej"); multimap.put("Nowak","Jan"); multimap.put("Nowak","Jerzy"); multimap.put("Nowak","Adam"); |
Utworzyliśmy „mapę”, która też ma klucz:wartość, ale klucz nie jest unikalny. I to jest całe piękno. Aby osiągnąć podobną funkcjonalność za pomocą zwykłej mapy, musielibyśmy jako wartość dać listę, przy dodawaniu elementów musielibyśmy sprawdzać, czy klucz, wartości, już nie istnieją, logika do bani, kto pisał ten wie, że to jest po prostu niewygodne.
Jeśli w jakimś momencie potrzebujemy jednak zrobić z tego mapę, guava daje nam taką możliwość:
1 |
multimap.asMap(); |
dostaniemy piękną mapę jako <String,Collection<String>>, która będzie zawierała wszystko pięknie pogrupowane.
Jeśli chcemy sprawdzić, czy wpis istnieje, po prostu podajemy:
1 |
multimap.containsEntry("Kowalski","Jan"); |
Oczywiście mamy też proste metody do pobrania kluczy, wartości, sprawdzenia czy istnieje klucz, czy istnieje wartość itp. Tylko używać 🙂
BiMap
Czasem mamy taką sytuację, że i klucz i wartości w mapie są unikalne, i chcemy pobrać klucz należący do wartości. Jest to też czasochłonna operacja, musimy pisać logikę sprawdzającą czy wartość istnieje, pobierać klucz i ogólnie jest z tym sporo zabawy. BiMap nam w tym bardzo pomaga
1 2 3 4 |
BiMap<String,String> biMap = HashBiMap.create(); biMap.put("Jan","Kowalski"); biMap.put("Adam","Nowak"); biMap.inverse(); |
Dzięki metodzie inverse() możemy zamienić mapę w ten sposób, że klucz staje się wartością, a wartość kluczem 🙂
Table
Tablica. A co, jeśli kluczem są dwie wartości w mapie ? Tworzymy mało czystelną strukturę typu Map<Klucz:Map<Klucz,Wartosc>>. Operacje na tym to już się robi małe piekełko i łatwo o błąd. Guava udostępnia nam tablicę, gdzie mamy dwa klucze, tak jak w tablicy zwykłej, mamy wiersze i kolumny, a wartość jest na przecięciu tych dwóch wartości…
1 2 3 4 5 6 7 8 9 |
Table<Integer,Integer,Integer> table = HashBasedTable.create(); table.put(1,1,1); table.put(1,2,2); table.put(1,3,3); table.put(2,1,1); table.put(2,2,2); table.put(2,3,3); System.out.println(table.column(1)); System.out.println(table.row(1)); |
piękne prawda? Pierwsza wartość to wiersz, druga to kolumna, a trzecia to wartość pary wiersz:kolumna
Proste i jakże przydatne !
Immutables
Na koniec bardzo ważna i przydatna właściwość kolekcji guava. Możemy tworzyć kolekcje, które są immutable – to znaczy kolekcje, których nie możemy zmienić! Przydaje się bardzo przy programowaniu funkcyjnym, gdzie z założenia elementy powinny być immutable.
1 |
ImmutableList<Integer> immutableList = ImmutableList.copyOf(Lists.newArrayList(1,2,3)); |
Czyli tworzymy listę, która nie może być zmieniona. Proste.
Tak samo możemy robić z setem, multisetem, mapą, multimapą, biMapą …