EnumSet i EnumMap
Używaj EnumSet i EnumMap do wydajnej i bezpiecznej typowo obsługi kolekcji opartych na enumach.
EnumSet i EnumMap to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
EnumSet i EnumMap
EnumSet i EnumMap to wysoce zoptymalizowane implementacje kolekcji przeznaczone dla enumów. Wewnętrznie używają wektorów bitowych — są znacznie szybsze niż HashSet i HashMap w przypadku kluczy będących enumami.
EnumSet: tworzenie zbiorów
EnumSet udostępnia metody fabryczne do tworzenia zbiorów stałych enuma.
import java.util.*;
enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
EnumSet<Day> weekdays = EnumSet.range(Day.MON, Day.FRI);
EnumSet<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);
EnumSet<Day> allDays = EnumSet.allOf(Day.class);
EnumSet<Day> noDays = EnumSet.noneOf(Day.class);
System.out.println(weekdays); // [MON, TUE, WED, THU, FRI]
System.out.println(weekend); // [SAT, SUN]
System.out.println(allDays.size()); // 7EnumSet: operacje na zbiorach
EnumSet obsługuje standardowe operacje na zbiorach — sumę, część wspólną i dopełnienie. Są one niezwykle szybkie dzięki implementacji opartej na wektorze bitowym.
import java.util.*;
enum Permission { READ, WRITE, DELETE, ADMIN, EXPORT }
EnumSet<Permission> userPerms = EnumSet.of(Permission.READ, Permission.WRITE);
EnumSet<Permission> adminPerms = EnumSet.allOf(Permission.class);
// Complement
EnumSet<Permission> missing = EnumSet.complementOf(userPerms);
System.out.println("Missing: " + missing);
// Missing: [DELETE, ADMIN, EXPORT]
// Intersection (retain)
EnumSet<Permission> shared = EnumSet.copyOf(userPerms);
shared.retainAll(adminPerms);
System.out.println("Shared: " + shared); // [READ, WRITE]EnumMap: mapowanie enumów na wartości
EnumMap wewnętrznie używa wartości ordinal enuma jako indeksu tablicy — wyszukiwanie w czasie O(1) jest szybsze niż w HashMap.
import java.util.*;
enum Quarter { Q1, Q2, Q3, Q4 }
EnumMap<Quarter, Double> revenue = new EnumMap<>(Quarter.class);
revenue.put(Quarter.Q1, 125_000.0);
revenue.put(Quarter.Q2, 148_500.0);
revenue.put(Quarter.Q3, 132_750.0);
revenue.put(Quarter.Q4, 175_200.0);
double total = revenue.values().stream()
.mapToDouble(Double::doubleValue).sum();
System.out.printf("Annual revenue: $%.0f%n", total);
// Annual revenue: $581450EnumMap: iterowanie w kolejności
EnumMap zawsze iteruje po kluczach w kolejności deklaracji enuma — nie w kolejności dodawania ani kolejności wynikającej z funkcji skrótu.
import java.util.*;
enum Month { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC }
EnumMap<Month, Integer> salesUnits = new EnumMap<>(Month.class);
salesUnits.put(Month.MAR, 1420);
salesUnits.put(Month.JAN, 980);
salesUnits.put(Month.FEB, 1105);
// Iterates JAN, FEB, MAR (declaration order, not insertion order)
for (var entry : salesUnits.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// JAN: 980
// FEB: 1105
// MAR: 1420System uprawnień z użyciem EnumSet
System uprawnień oparty na rolach, wykorzystujący EnumSet do wydajnego sprawdzania uprawnień i przejrzystego projektowania API.
import java.util.*;
enum Permission { READ, WRITE, DELETE, PUBLISH, ADMIN }
record Role(String name, EnumSet<Permission> permissions) {
boolean can(Permission p) { return permissions.contains(p); }
}
Role editor = new Role("Editor",
EnumSet.of(Permission.READ, Permission.WRITE, Permission.PUBLISH));
Role viewer = new Role("Viewer",
EnumSet.of(Permission.READ));
System.out.println(editor.can(Permission.WRITE)); // true
System.out.println(viewer.can(Permission.DELETE)); // falseFlagi funkcji z użyciem EnumMap
EnumMap doskonale nadaje się do systemów flag funkcji: zapewnia szybkie wyszukiwanie w czasie O(1) dla kluczy będących enumami.
import java.util.*;
enum Feature { DARK_MODE, BETA_EDITOR, AI_SUGGESTIONS, EXPORT_PDF }
class FeatureFlags {
private final EnumMap<Feature, Boolean> flags = new EnumMap<>(Feature.class);
public FeatureFlags() {
for (Feature f : Feature.values()) flags.put(f, false);
}
public void enable(Feature f) { flags.put(f, true); }
public void disable(Feature f) { flags.put(f, false); }
public boolean isEnabled(Feature f) { return flags.getOrDefault(f, false); }
}
FeatureFlags ff = new FeatureFlags();
ff.enable(Feature.DARK_MODE);
System.out.println(ff.isEnabled(Feature.DARK_MODE)); // true
System.out.println(ff.isEnabled(Feature.AI_SUGGESTIONS)); // falseWydajność: EnumSet a HashSet
EnumSet używa pojedynczej maski bitowej typu long (dla enumów zawierających <=64 stałe) — operacje są operacjami bitowymi wykonywanymi w czasie O(1). HashSet używa kubełków funkcji skrótu, co wiąże się z mniejszą szybkością i większym narzutem.
import java.util.*;
enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
// EnumSet: bit operations on a long value
EnumSet<Day> workDays = EnumSet.range(Day.MON, Day.FRI);
// HashSet: hash table with boxing overhead
Set<Day> hashWorkDays = new HashSet<>(Arrays.asList(
Day.MON, Day.TUE, Day.WED, Day.THU, Day.FRI));
// Both work, but EnumSet is ~5x faster for contains/add/remove
// and uses less memory
System.out.println(workDays.contains(Day.SAT)); // false
System.out.println(workDays.contains(Day.MON)); // truegetOrDefault i computeIfAbsent w EnumMap
EnumMap obsługuje wszystkie operacje Map, w tym getOrDefault, computeIfAbsent i merge.
import java.util.*;
enum Category { FOOD, ELECTRONICS, CLOTHING, BOOKS }
EnumMap<Category, List<String>> catalog = new EnumMap<>(Category.class);
// computeIfAbsent creates the list on first use
catalog.computeIfAbsent(Category.BOOKS, k -> new ArrayList<>()).add("Clean Code");
catalog.computeIfAbsent(Category.BOOKS, k -> new ArrayList<>()).add("Effective Java");
catalog.computeIfAbsent(Category.ELECTRONICS, k -> new ArrayList<>()).add("Laptop");
System.out.println(catalog.get(Category.BOOKS));
// [Clean Code, Effective Java]
System.out.println(catalog.getOrDefault(Category.FOOD, List.of()));
// []Wzorzec multimap z EnumMap
Połącz EnumMap z wartościami typu List, aby utworzyć multimapę z kluczami będącymi enumami — wydajne grupowanie elementów według kategorii.
import java.util.*;
import java.util.stream.*;
enum Priority { LOW, NORMAL, HIGH, URGENT }
record Task(String name, Priority priority) {}
List<Task> tasks = List.of(
new Task("Fix login bug", Priority.URGENT),
new Task("Update docs", Priority.LOW),
new Task("Add unit tests",Priority.NORMAL),
new Task("Deploy hotfix", Priority.URGENT)
);
// Group by priority into EnumMap
EnumMap<Priority, List<Task>> byPriority = tasks.stream()
.collect(Collectors.groupingBy(Task::priority,
() -> new EnumMap<>(Priority.class),
Collectors.toList()));
byPriority.forEach((p, ts) ->
System.out.println(p + ": " + ts.stream().map(Task::name).collect(Collectors.joining(", "))));Kiedy używać EnumSet, a kiedy EnumMap
Podsumowanie, kiedy wybrać poszczególne rozwiązanie:
- EnumSet: gdy potrzebujesz zbioru wartości enuma — uprawnień, aktywnych funkcji lub wybranych dni
- EnumMap: gdy mapujesz każdą stałą enuma na wartość — konfigurację dla każdej funkcji, wynik dla każdego poziomu lub elementy dla każdej kategorii
- Oba rozwiązania: preferuj je zamiast HashSet i HashMap dla kluczy będących enumami — są szybsze, zajmują mniej pamięci i zachowują kolejność
Szybkie sprawdzenie
Jaka struktura danych jest używana wewnętrznie przez EnumSet dla enumów zawierających 64 lub mniej stałych?
Podsumowanie: EnumSet i EnumMap
Najważniejsze informacje:
- EnumSet używa wektora bitowego — jest niezwykle szybki dla małych zbiorów enumów
- EnumSet.of(), range(), allOf() i noneOf() to często używane metody fabryczne
- EnumMap używa tablic indeksowanych za pomocą ordinal — zapewnia wyszukiwanie w czasie O(1) i kolejność zgodną z deklaracją
- Używaj EnumSet dla zbiorów uprawnień, flag funkcji i filtrowania dni tygodnia
- Używaj EnumMap dla konfiguracji według kategorii, tabel wyników i mapowania funkcji na wartości
- Obie kolekcje zachowują kolejność deklaracji enuma i są wydajniejsze niż kolekcje oparte na funkcji skrótu
Często zadawane pytania
Czy lekcja „EnumSet i EnumMap” jest bezpłatna?
Tak — pełny tekst „EnumSet i EnumMap” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „EnumSet i EnumMap”?
Używaj EnumSet i EnumMap do wydajnej i bezpiecznej typowo obsługi kolekcji opartych na enumach. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „EnumSet i EnumMap”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.