Bit Field
- 열거한 값들이 주로 집합으로 사용될 경우가 존재합니다. 예를 들면 CSS의 style과 같은 것이 그러합니다. 여러 값들이 포함될 수 있기 때문입니다.
- Enum이 없었을 때에는 이를 비트필드라고 하는 방식을 사용하여 구현했었습니다.
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;
public void apply(int styles) {
...
}
}
- 이때 styles는 여러 값들이 포함된 값입니다. 이를 표현하기 위해 or 연산을 사용합니다. 예를 들어 BOLD와 ITALIC를 같이 포함시키고 싶다면
STYLE_BOLD | STYLE_ITALIC
을 styles에 넣는 것입니다.
- 이는 비트별 연산을 통해 합집합과 교집합같은 집합 연산을 효율적으로 수행할 수 있습니다.
- 하지만 비트필드 방식은 정수 열거 패턴의 한 종류이기 때문에 정수 열거 패턴의 단점을 그대로 가져가며, 비트 필드 값이 그대로 출력될 경우 해석에 매우 어려움을 겪을 수 있습니다.
- 그 뿐만 아니라 상수가 몇개인지에 따라 최대 몇 비트가 필요한지를 미리 예측하여 지정해야 합니다. 만약 위의 클래스가 API로 배포된 뒤에 새로운 상수가 추가되어야 할 경우 이를 변경하기가 매우 힘들어질 수 있다는 것입니다.
- 이를 해결하기 위해 EnumSet이라는 클래스가 나왔습니다. 이는 말 그대로 Enum 타입의 집합을 의미하며 위와 같이 여러 열거 타입의 집합을 효과적으로 표현합니다.
- EnumSet은 Set 인터페이스를 구현한 것으로 타입 안전하고 다른 Set 구현체와도 함께 사용이 가능합니다.
- 하지만 내부 구현을 보면 EnumSet이 비트필드 방식을 사용하여 구현된 것을 확인할 수 있습니다. 즉 EnumSet 은 비트필드 방식의 장점 중 하나인 교집합과 합집합 연산을 효율적으로 수행할 수 있다는 것에 더해 타입 안정성과 난해한 작업들을 모두 처리해주는 클래스가 됩니다.
- 위의 코드를 EnumSet으로 구현한 코드는 아래와 같습니다.
public class Text {
public enum Style
BOLD, ITALIC , UNDERLINE, STRIKETHROUGH;
}
public void apply(Set<Style> styles){...}
}
public class Client {
public static void main(String[] args) {
Text text = new Text();
text.apply(EnumSet.of(Style.BOLD. Style.ITALIC));
}
}