0Pricing
Java Academy · 강의

EnumSet과 EnumMap

효율적이고 유형 안전한 열거형 기반 컬렉션에 EnumSet과 EnumMap을 사용합니다.

EnumSet과 EnumMap은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

EnumSet과 EnumMap

EnumSet과 EnumMap은 열거형에 맞게 고도로 최적화된 컬렉션 구현입니다. 내부적으로 비트 벡터를 사용하므로 열거형 키에 HashSet/HashMap을 사용하는 것보다 훨씬 빠릅니다.

EnumSet: 집합 만들기

EnumSet은 열거형 상수 집합을 만드는 팩토리 메서드를 제공합니다.

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: 집합 연산

EnumSet은 표준 집합 연산인 합집합, 교집합, 여집합을 지원합니다. 이러한 연산은 비트 벡터 구현 덕분에 매우 빠릅니다.

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: 열거형을 값에 매핑하기

EnumMap은 내부적으로 열거형의 서수를 배열 인덱스로 사용하므로 O(1) 조회가 가능하며 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: $581450

EnumMap: 순서대로 순회하기

EnumMap은 삽입 순서나 해시 순서가 아니라 항상 열거형 선언 순서대로 키를 순회합니다.

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

EnumSet을 사용하는 권한 시스템

효율적인 권한 확인과 깔끔한 API 설계를 위해 EnumSet을 사용하는 역할 기반 권한 시스템입니다.

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

EnumMap을 사용하는 기능 플래그

EnumMap은 기능 플래그 시스템에 적합합니다. 열거형 키를 사용해 O(1) 조회가 빠르게 이루어집니다.

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

성능: EnumSet과 HashSet 비교

EnumSet은 상수가 64개 이하인 열거형에 하나의 long 비트 마스크를 사용하므로 연산이 O(1) 비트 연산으로 처리됩니다. HashSet은 해시 버킷을 사용하므로 더 느리고 추가 오버헤드가 발생합니다.

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와 computeIfAbsent

EnumMap은 getOrDefault, computeIfAbsent, merge를 비롯한 모든 Map 연산을 지원합니다.

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

EnumMap을 사용하는 다중 맵 패턴

EnumMap을 List 값과 결합하면 열거형을 키로 사용하는 다중 맵을 만들 수 있어 카테고리별 항목을 효율적으로 그룹화할 수 있습니다.

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

EnumSet과 EnumMap을 사용하는 경우

각각을 선택할 기준은 다음과 같습니다:

  • EnumSet: 권한, 활성 기능, 선택한 요일처럼 열거형 값의 집합이 필요할 때
  • EnumMap: 기능별 설정, 등급별 점수, 카테고리별 항목처럼 각 열거형 상수를 값에 매핑할 때
  • 둘 다: 열거형 키에는 HashSet/HashMap보다 빠르고 메모리를 적게 사용하며 순서를 유지하므로 우선 고려합니다

빠른 확인

상수가 64개 이하인 열거형에서 EnumSet이 사용하는 내부 데이터 구조는 무엇인가요?

복습: EnumSet과 EnumMap

핵심 내용:

  • EnumSet은 비트 벡터를 사용하므로 작은 열거형 집합에서 매우 빠릅니다
  • EnumSet.of(), range(), allOf(), noneOf()는 자주 사용하는 팩토리 메서드입니다
  • EnumMap은 서수로 인덱싱된 배열을 사용하므로 O(1) 조회가 가능하고 선언 순서대로 정렬됩니다
  • 권한 집합, 기능 플래그, 요일 필터링에는 EnumSet을 사용합니다
  • 카테고리별 설정, 점수표, 기능과 값의 매핑에는 EnumMap을 사용합니다
  • 둘 다 열거형 선언 순서를 유지하며 해시 기반 컬렉션보다 효율적입니다

자주 묻는 질문

“EnumSet과 EnumMap” 강의는 무료인가요?

네 — “EnumSet과 EnumMap” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“EnumSet과 EnumMap”에서 뭘 배우나요?

효율적이고 유형 안전한 열거형 기반 컬렉션에 EnumSet과 EnumMap을 사용합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Java Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“EnumSet과 EnumMap” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 열거형 정의와 사용
  2. 필드와 메서드를 포함한 열거형
  3. 열거형을 사용한 switch 표현식
  4. EnumSet과 EnumMap
← Java Academy(으)로 돌아가기