Java Academy · Oppitunti

EnumSet ja EnumMap

Käytä EnumSet- ja EnumMap-kokoelmia tehokkaaseen ja tyyppiturvalliseen enum-pohjaiseen käsittelyyn.

Oppitunti 4/413 vaihetta

EnumSet ja EnumMap on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

EnumSet ja EnumMap

EnumSet ja EnumMap ovat erittäin optimoituja enumien kokoelmatoteutuksia. Ne käyttävät sisäisesti bittivektoreita — enum-avaimia käytettäessä ne ovat paljon nopeampia kuin HashSet/HashMap.

EnumSet: joukkojen luominen

EnumSet tarjoaa tehdasmetodeja enum-vakioiden sisältämien joukkojen luomiseen.

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()); // 7

EnumSet: joukko-operaatiot

EnumSet tukee tavallisia joukko-operaatioita — unionia, leikkausta ja komplementtia. Bittivektoritoteutuksen ansiosta nämä operaatiot ovat erittäin nopeita.

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: enumien yhdistäminen arvoihin

EnumMap käyttää sisäisesti enum-vakiota taulukon indeksinä — haku on O(1) ja nopeampaa kuin HashMapissa.

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: $581450

EnumMap: iterointi järjestyksessä

EnumMap käy avaimet aina läpi enumien määritysjärjestyksessä — ei lisäys- tai hash-järjestyksessä.

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: 1420

Käyttöoikeusjärjestelmä EnumSetillä

Roolipohjainen käyttöoikeusjärjestelmä, jossa EnumSetiä käytetään tehokkaisiin käyttöoikeustarkistuksiin ja selkeään API-suunnitteluun.

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)); // false

Ominaisuusliput EnumMapillä

EnumMap sopii erinomaisesti ominaisuuslippujärjestelmiin: enum-avaimilla saadaan nopea O(1)-haku.

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)); // false

Suorituskyky: EnumSet vs. HashSet

EnumSet käyttää yhtä long-bittimaskia (enum-tyypeille, joissa on <=64 vakiota) — operaatiot ovat O(1)-bittioperaatioita. HashSet käyttää hash-ämpäreitä, joten siinä on enemmän ylimääräistä käsittelyä ja se on hitaampi.

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));     // true

EnumMap getOrDefault ja computeIfAbsent

EnumMap tukee kaikkia Map-operaatioita, kuten getOrDefault-, computeIfAbsent- ja merge-operaatioita.

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()));
// []

Multimap-malli EnumMapillä

Yhdistämällä EnumMapin List-arvoihin voitte luoda enum-avaimellisen multimapin, jolla alkiot ryhmitellään tehokkaasti luokan mukaan.

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(", "))));

Milloin käyttää EnumSetiä ja milloin EnumMapiä

Yhteenveto valintaperusteista:

  • EnumSet: kun tarvitsette enum-arvojen joukon — esimerkiksi käyttöoikeuksia, aktiivisia ominaisuuksia tai valittuja viikonpäiviä
  • EnumMap: kun yhdistätte jokaisen enum-vakion arvoon — esimerkiksi ominaisuuskohtaisiin asetuksiin, tasokohtaisiin pisteisiin tai luokkakohtaisiin alkioihin
  • Molemmat: suosikaa niitä HashSetin/HashMapin sijaan enum-avaimilla — ne ovat nopeampia, käyttävät vähemmän muistia ja säilyttävät järjestyksen

Pikatarkistus

Mitä sisäistä tietorakennetta EnumSet käyttää enum-tyypeille, joissa on enintään 64 vakiota?

Kertaus: EnumSet ja EnumMap

Tärkeimmät opit:

  • EnumSet käyttää bittivektoria — se on erittäin nopea pienille enum-joukoille
  • EnumSet.of(), range(), allOf() ja noneOf() ovat yleisiä tehdasmetodeja
  • EnumMap käyttää ordinaalin mukaan indeksoituja taulukoita — haku on O(1), ja avaimet ovat määritysjärjestyksessä
  • Käyttäkää EnumSetiä käyttöoikeusjoukkoihin, ominaisuuslippuihin ja viikonpäivien suodatukseen
  • Käyttäkää EnumMapiä luokkakohtaisiin asetuksiin, pisteytystaulukoihin ja ominaisuuden yhdistämiseen arvoon
  • Molemmat säilyttävät enumien määritysjärjestyksen ja ovat tehokkaampia kuin hash-pohjaiset kokoelmat
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”EnumSet ja EnumMap” ilmainen?

Kyllä – oppitunnin ”EnumSet ja EnumMap” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”EnumSet ja EnumMap”?

Käytä EnumSet- ja EnumMap-kokoelmia tehokkaaseen ja tyyppiturvalliseen enum-pohjaiseen käsittelyyn. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”EnumSet ja EnumMap”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Enum-tyyppien määrittäminen ja käyttäminen
  2. Kentät ja metodit enum-tyypeissä
  3. Switch-lausekkeet enum-tyypeillä
  4. EnumSet ja EnumMap
← Takaisin: Java Academy