Item 36 - 비트 필드 대신 EnumSet을 사용하라
비트 필드 열거 상수
열거한 값들이 집합으로 사용될 경우,
예전에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용해왔다.
1
2
3
4
5
6
7
8
9
10
11
12
// 비트 필드 열거 상수 - 구닥다리 기법
public class Text {
public static final int STYLE_BOLD = 1 << 0;
public static final int STYLE_ITALIC = 1 << 1;
public static final int STYLE_UNDERLINE = 1 << 2;
public static final int STYLE_STRIKETHROUGH = 1 << 3;
// 매개변수는 0개 이상의 STYLE_ 상수를 비트별 OR한 값
public void applyStyles(int styles) {
// ...
}
}
1
text.applyStyles(BOLD | UNDERLINE); // 여러 상수를 하나의 집합으로 모으는 방법 (비트 필드)
- 비트 필드 값 하나로는 단순한 정수 열거 상수를 출력할 때보다 값의 의미를 해석하기 어렵다.
- 비트 필드 하나에 녹아 있는 모든 원소를 순회하기도 까다롭다.
- 최대 몇 비트가 필요한 지를 API 작성 시 미리 예측하여 적절한 타입을 선택해야 한다.
- 보통은 int or long … (32비트 or 64비트…)
- API를 수정하지 않고는 비트 수를 더 늘릴 수 없기 때문이다.
[더 나은 대안] EnumSet
- 열거 타입 상수의 값으로 구성된 집합을 효과적으로 표현해준다.
Set
인터페이스를 완벽히 구현하며, 타입 안전하다.- 내부가 비트 벡터로 구성되어 있다.
- 원소가 64개 이하면,
EnumSet
전체를long
변수 하나로 표현하여 비트 필드와 비슷한 성능을 보여준다.
- 원소가 64개 이하면,
앞선 예시를 EnumSet
을 사용해 짧고 깔끔하게 바꿀 수 있다.
1
2
3
4
5
6
7
8
9
10
public class Text {
public enum Style {
BOLD, ITALIC, UNDERLINE, STRIKETHROUGH
}
// 어떤 Set을 넘겨도 되나, EnumSet이 가장 좋다.
public void applyStyles(Set<Style> styles) {
// ...
}
}
- 매개변수로
EnumSet<Style>
이 아닌Set<Style>
을 받은 이유?- 이왕이면 인터페이스로 받는 게 일반적으로 좋은 습관이다. (아이템 64)
- 클라이언트가 다른
Set
구현체를 넘기더라도 처리할 수 있기 때문이다.
1
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
💡 핵심 정리
- 열거할 수 있는 타입을 한데 모아 집합 형태로 사용할 때는 EnumSet 클래스를 사용하자.
EnumSet
의 유일한 단점은 불변EnumSet
을 만들 수 없다는 것이다.Collections.unmodifiableSet
으로EnumSet
을 감싸 사용할 수 있다.
This post is licensed under CC BY 4.0 by the author.