EnumSet
Skoro rozpoczęliśmy temat typów wyliczeniowych to również warto powiedzieć o kolekcji EnumSet.
Znasz już jedną kolekcję – jest to Lista – np. LinkedList lub ArrayList. Listy są po prostu zbiorem wszystkich wartości, które się dodaje – lecz, czym jest set?
Set
Zacznijmy od tego czym jest set – jest zbiorem tylko unikalnych obiektów!
Przypuśćmy, że mamy set (zbiór) studentów, gdzie każdy ma przypisany do siebie unikalny numer studenta – w takim zbiorze, więc nie ma miejsca na duplikację elementów – jeśli będzie próba dodania studenta o tym samym numerze to się on po prostu nie doda.
Jak działają porównania czy obiekty są takie same?
Oczywiście na początek wchodzi porównanie referencji czyli adresów np.:
Object s1 = new Object(); Object s2 = new Object(); if (s1 == s2);
Jeśli warunek zostanie spełniony to obiekty są porównywane metodą equals – czyli jest sprawdzana zawartość obiektu, według naszego wcześniej przedstawionego schematu. Wystarczy, że w metodzie equals będzie tylko sprawdzenie równości numeru studenta i nasz set będzie działał poprawnie.
EnumSet
Skoro wiesz teoretycznie czym jest kolekcja set to można przejść do EnumSet – a to po prostu zbiór na enumy.
Oczywiście enumy można przechowywać w zwykłych listach lub tablicach, ale pytanie po co? – skoro mamy do tego już stworzone kolekcje.
A może EnumList…
Skoro jest zwykła lista dla obiektów to może istnieje również lista na typów wyliczeniowych? W końcu co w sytuacji, gdy chcemy przechowywać duplikaty?
Ten case jest całkowicie bez sensu, w końcu założeniem typu wyliczeniowego jest unikalność – czyli bycie singletonem. W takim razie enum powinien być przechowywany np. w EnumSet zamiast w zwykłych listach, które spowodują duplikację elementów.
Jeszcze nie wyobrażasz sobie tego?
Lista wyboru
Przypuśćmy, że mamy w magazynie bluzę, która jest w kolorach RED, BLUE, GREEN – oczywiście kolory są trzymane w enum – jak przystało na dobrego programiste.
Trzymanie listy kolorów w zwykłej liście (choć mamy listę kolorów :P) jest złym pomysłem, ponieważ, może dojść do duplikacji kolorów i na interfejsie użytkownika (UI) zostaną wyświetlone te same kolory kilkukrotnie, a tego oczywiście nie chcemy.
Zaczynajmy!
Oczywiście skoro chcemy przechowywać enumy to trzeba je najpierw mieć – przywołajmy kolory z poprzedniej lekcji:
package pl.maniaq; import java.awt.*; public enum Colors implements ColorOperations{ RED(255, 0, 0), GREEN(0, 255, 0), BLUE(0, 0, 255), YELLOW(255, 204, 0); private int red; private int green; private int blue; Colors(int red, int green, int blue) { this.red=red; this.green=green; this.blue=blue; } @Override public String getHexColor() { return "#"+Integer.toHexString(getRGB()); } @Override public int getRGB() { return new Color(red, green, blue).getRGB(); } }
Gdy mamy już typ wyliczeniowy to możemy przejść do stworzenia kolekcji EnumSet – robi się to trochę w inny sposób niż normalnie – albowiem bez konstruktora tylko przez statyczną metodę. Podobnie, gdy robiliśmy singletony. 😉
EnumSet<Colors> colors = EnumSet.noneOf(Colors.class);
Metoda noneOf tworzy nam pustego enuma dla typ, który przekazujemy jako argument – w naszym przypadku jest to Colors.class.
Możemy również użyć metody allOf, który stworzy automatycznie zbiór wraz ze wszystkimi elementami danego enuma:
EnumSet<Colors> colors = EnumSet.allOf(Colors.class);
Choć my zostaniemy przy pustym zbiorze:
EnumSet<Colors> colors = EnumSet.noneOf(Colors.class);
I metodą add dodamy do niego dwa kolory:
colors.add(Colors.RED); colors.add(Colors.BLUE);
Sprawdzimy czy w naszym zbiorze jest kolor niebieski metodą contains – czyli zawiera:
if (colors.contains(Colors.BLUE)) { System.out.println("Jest kolor niebieski!"); }
Usuniemy kolor czerwony metodą remove:
colors.remove(Colors.RED);
Sprawdzimy czy kolekcja nie jest pusta negacją rezultatu metody isEmpty:
if (!colors.isEmpty()) { System.out.println("Kolekcja nie jest pusta!"); }
Metodą size możemy jeszcze sprawdzić ilość elementów w kolekcji:
System.out.println("Ilość elementów: " + colors.size());
Oraz na koniec wyświetlimy zawartość zbioru:
System.out.println("Elementy: " + colors.toString());
Po wszystkich operacjach nasz kod wygląda tak:
package pl.maniaq; import java.util.EnumSet; public class Main { public static void main(String[] args) { EnumSet<Colors> colors = EnumSet.noneOf(Colors.class); colors.add(Colors.RED); colors.add(Colors.BLUE); if (colors.contains(Colors.BLUE)) { System.out.println("Jest kolor niebieski!"); } colors.remove(Colors.RED); if (!colors.isEmpty()) { System.out.println("Kolekcja nie jest pusta!"); } System.out.println("Ilość elementów: " + colors.size()); System.out.println("Elementy: " + colors.toString()); } }
A po uruchomieniu otrzymujemy:
Jest kolor niebieski! Kolekcja nie jest pusta! Ilość elementów: 1 Elementy: [BLUE]
Jak widać wszystko śmiga poprawnie.
Podsumowanie
Pokazałem Ci jedną z głównym kolekcji do przechowywania typów wyliczeniowych – EnumSet. Pamiętaj również do c zego służy Set, ponieważ dużo częściej będziesz korzystał ze zwykłego seta i implementancji takich jak: HashSet oraz TreeSet przeznaczone do przechowywania zwykłych obiektów.
Dodatkowo istnieje jeszcze EnumMap, jest to również specjalny typ kolekcji – mapa, o której opowiem już na innym przykładzie, a nie koniecznie na EnumMap. 😉
Jeśli chcesz przyswoisz jeszcze lepiej wiedzę z EnumSet to wykonaj poniższe zadanie:
- Stwórz enum: Operations wraz z takimi obiektami jak: CREATE, EDIT, CLOSE, ON, SAVE, OFF, COPY, PASTE, CUT, HIBERNATE.
- Stwórz w klasie Main EnumSet o nazwie computerOperations oraz dodaj do niego obiekty: ON, OFF, HIBERNATE, COPY, PASTE, CUT.
- Stwórz w klasie Main EnumSet o nazwie textEditorOperations oraz dodaj do niej obiekty: CREATE, COPY, PASTE, CUT, SAVE.
- Stwórz w klasie Main EnumSet o nazwie allOperations wraz ze wszystkimi operatorami z enuma.
- Usuń z allOperations obiekt CREATE, ON, OFF.
- Wyświetl wszystkie obiekt z obu zbiorów oraz rozmiary tych zbiorów.
Moje przykładowe rozwiązanie zadania możesz zobaczyć tutaj.