[Effective Java] 6 - item 36 비트 필드 대신 EnumSet을 사용하라.
비트 필드 열거 상수
public class Text {
public static final int STYLE_BOLD = 1 << 0; //1
public static final int STYLE_ITALIC = 1 << 1; //2
public static final int STYLE_UNDERLINE = 1 << 2; //4
public static final int STYLE_STRIKETHROUGH = 1 << 3; //8
//매개 변수 styles는 0개 이상의 STYLE_ 상수를 비트별 OR 한 값이다.
public void applyStyle(int styles) {...}
}
열거한 값들이 집합으로 사용될 경우 예전에는 정수 열거 패턴을 사용했다.
text.applyStyles(STYLE_BOLD | STYLE_ITALIC); // 1 | 2 => 3
이런 식으로 비트 연산을 적용해 여러 상수를 하나의 집합으로 선택할 수 있었고, 이를 비트 필드라 한다.
비트 필트
- 비트 필드를 사용하면 비트 연산(AND, OR, …)을 사용해 합집합, 교집합 등의 집합 연산을 효율적으로 수행할 수 있다.
하지만…
- 정수 열거 상수의 단점을 그대로 지니고 있다.
- type-safe하지 않고, 값 변경되면 다시 컴파일 하는 과정이 필요하다
- 비트 필드 값이 그대로 출력되면 단순한 정수 열거 상수를 출력할 때보다 의미 파악이 훨씬 어렵다.
- 비트 필드 하나에 할당된 모든 원소 순회가 까다롭다.
- 최대 몇 비트가 필요한지, API 작성 시에 미리 예측해 적절한 타입(
int, long ...
)을 선택해야 한다.- 한번 정하고 나면 비트 수 더 늘리기 어려움
EnumSet
- 열거 타입 상수로 구성된 집합을 효과적으로 표현한다.
Set
인터페이스를 완벽히 구현하고 있으며, type-safe하고, 다른Set
구현체와 함께 사용 가능하다.- 비트 벡터로 구현되어 있다.
- 원소가 64개 이하인 경우,
EnumSet
전체를long
변수 하나로 표현하여 비트 필드에 비견되는 성능을 보여준다. removeAll
과retailAll
과 같은 대량 작업은 비트를 효율적으로 처리 할 수 있는 산술 연산으로 구현해 두었다.- 비트를 직접 다룰때 겪는 오류가 발생하지 않을 것이다.
public class Text {
public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
// 어떤 Set을 넘겨도 되나 EnumSet이 가장 좋다.
// 다른 Set 구현체 처리를 위해 이왕이면 Set Interface로 받는게 좋다.
public void applyStyles(Set<Style> styles) {...}
}
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
Leave a comment