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()); // 7EnumSet: 집합 연산
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: $581450EnumMap: 순서대로 순회하기
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: 1420EnumSet을 사용하는 권한 시스템
효율적인 권한 확인과 깔끔한 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)); // falseEnumMap을 사용하는 기능 플래그
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)); // trueEnumMap의 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 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 열거형 정의와 사용
- 필드와 메서드를 포함한 열거형
- 열거형을 사용한 switch 표현식
- EnumSet과 EnumMap