열거한 값들이 주로 집합으로 사용되는 경우 예전에는 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용했다.
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; //
// 매개변수 styles는 0개 이상의 STYLE_ 상수를 비트별 OR 한 값이다.
public void applyStyles(int styles){...}
}
.
.
.
text.applyStyles(STYLE_BOLD | STYLE_ITALIC);
다음과 같은 식으로 비트별 OR를 사용해 여러 상수를 하나의 집합으로 모을 수 있고, 이렇게 만들어진 집합을 비트 필드
이라고 한다.
비트 필드
를 사용하면 교집합이나 합집합 같은 집합 연산을 효율적으로 수행할 수 있지만 정수 열거 상수의 단점을 그대로 지니고 추가로 다음과 같은 문제까지 안고 있다.
비트 필드
값이 그대로 출력되면 단순 정수 열거 패턴보다 해석하기 어렵다.비트 필드
하나에 녹아 있는 모든 원소를 순회하기 까다롭다.java.util의 EnumSet 클래스는 이를 완벽하게 대체한다. 열거 타입 상수 값으로 구성된 집합을 효과적으로 표현해준다. Set 인터페이스를 완벽히 구현하고, 타입 안전하며, 다른 Set 구현체와 같이 사용할 수도 있다.
내부가 비트 벡터로 구현되어 있어서 대부분의 경우 removeAll과 retainAll 같은 대량 작업을 비트 필드에 비견되는 성능으로 처리할 수 있다.
앞의 코드를 EnumSet으로 수정한 코드를 보자.
public class Text{
public enum Style {BOLD, ITALIC, UNDERLINE, STRIKETHROUGH}
// 어떤 Set을 넘겨도 상관없지만, EnumSet이 가장 좋다.
public void applyStyles(Set<Style> style){...}
}
.
.
.
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
모든 클라이언트가 EnumSet이라고 예상되더라고 인터페이스인 Set을 받는게 좋은 습관이다. 특이한 클라이언트가 다른 Set 구현체를 넘기더라도 처리할 수 있으니 말이다.