(Effective Java 2/E) 138. Item 32 - Use EnumSet instead of bit fields

Use EnumSet instead of bit fields

  • 2판 제목 : 비트 필드(bit field) 대신 EnumSet을 사용하라
  • 3판 제목 : 비트 필드 대신 EnumSet을 사용하라

1. 전통적인 enum pattern에서의 활용

열거 자료형의 원소들이 주로 집합에 사용되는 경우, int enum pattern 에서는 아래와 같이 사용되었다.

1
2
3
4
5
6
7
8
9
// Bit field enumeration constants - OBSOLETE!
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
// Parameter is bitwise OR of zero or more STYLE_ constants
public void applyStyles(int styles) { ... }
}

각 상수에 2의 거듭제곱을 대입한 것인데, 이를 이용하면 상수들을 bitwise 연산에 사용할 수 있다.

예를 들면 아래와 같이 BOLD와 ITALIC을 동시에 적용하는 경우이다.

1
text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

이렇게 집합을 비트 필드로 나타내면 비트 단위 산술 연산(bitwise arithmetic) 에 사용할 수 있다.

하지만 비트 필트는 int enum pattern과 동일한 단점을 그대로 가지고 있다.

2. EnumSet

비트 필드의 목적을 달성하면서도 단점을 해소하기 위해 자바 1.5부터는 EnumSet이라는 자료구조를 제공한다.

EnumSet을 활용하면 특정한 enum 자료형의 값으로 구성된 집합을 효율적으로 표현할 수 있다.

이 클래스는 Set 인터페이스를 구현하고있기 때문에 Set의 기본 기능과 타입 안정성 및 상호운용성(interoperability)도 함께 제공한다.

내부적으로는 비트 벡터(bit vector)를 사용하기 대문에 enum의 개수가 64개 이하인 경우 long 하나로 모든 비트를 표현한다.

위의 예제를 EnumSet으로 교체하면 아래와 같다.

1
2
3
4
5
6
7
8
9
// EnumSet - a modern replacement for bit fields
public class Text {
public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }

// Any Set could be passed in, but EnumSet is clearly best
public void applyStyles(Set<Style> styles) {
//...
}
}

호출은 아래와 같이 진행하면 된다.

1
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));

applyStyles()가 받는 파라미터 타입이 EnumSet<Style>이 아니라 Set<Style> 이라는 것에 유의해야한다.

3. 마무리

열거 자료형을 집합으로 사용해야한다고 해서 비트 필드로 표현하는 것은 곤란하다.