728x90
과거 ..
열거 값들이 집합으로 사용되는 경우 비트 마스킹을 활용한 정수 열거 패턴을 사용하곤 했다.
public class Text {
public static final int STYLE_BOLD = 1 << 0; // 1st : 1 (0001)
public static final int STYLE_ITALIC = 1 << 1; // 2nd : 2 (0010)
public static final int STYLE_UNDERLINE = 1 << 2; // 3rd : 4 (0011)
public static final int STYLE_STRIKETHROUGH = 1 << 3; // 4th : 8 (0100)
public void applyStyles(int styles) { //...}
}
}
- 클래스 안에 상수로 표현할 때 shift연산을 해서 비트로 표현하는 것. 이를 통해 상수 값을 비트로 표현할 수 있다.
- 또한, 아래와 같이 bit값으로 표현된 상수들을 OR연산해 합집합이나 교집합으로 표현할 수도 있다.
text.applyStyles(STYLE_BOLD | STYLE_ITALIC); // 1st, 2nd를 OR 연산함. 01 | 10 -> 11 (3)
왜 쓰면 안될까?
- 끔찍한(?) 정수 열거 패턴의 단점을 그대로 지니고 있다.
- 여기에 더해 비트 필드 값이 출력될 경우 더 해석하기 어렵다는 특징을 가지고 있다.
- 비트 필드 하나에 있는 모든 원소를 순회하는 것도 까다롭다.
- 최대 몇 비트가 필요한지 API작성 시 미리 예측하여 int/long 등 적절한 타입을 선택해야 한다.
- API를 수정하지 않고는 비트를 늘릴 수 없다.
대안은?
java.util 의 EnumSet 클래스 사용
장점!
- Enum 상수 값으로 구성된 집합을 효과적으로 표현하며
- Set 인터페이스도 완벽히 구현할 수 있다.
- 타입 안전하다.
- 다른 어떤 Set 구현체와도 함께 사용할 수 있다.
EnunmSet의 내부는 비트 벡터로 구현되어 있다. => 원소가 64개 이하라면 long하나로 표현할 수 있다. 비트 필드와 비견된 성능을 보여준다.
(낫고 못할 것이 없이 정도가 서로 비슷하게 견주어지다. 앞서거나 뒤서지 않고 어깨를 나란히 한다는 뜻) ㅎ
그러나 비트를 직접 다룰때 겪는 오류는 일어나지 않는다. EnumSet이 난해한 작업을 처리해주기 때문이다.
게다가, 정보도 그대로 가지고 있고 비트필드를 사용하면 할 수 없었던 순회도 할 수 있다.
public static void main(String[] args) {
//of method : EnumSet이 제공하는 정적 팩터리 메소드
Text.applyStyles(EnumSet.of(Text.Style.BOLD, Text.Style.ITALIC, Text.Style.UNDERLINE));
}
public class Text {
public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
"클라이언트가 다른 Set 구현체를 넘기더라도 처리할 수 있게
EnumSet보단 Set<Style>을 사용하는 것이 좋은 습관이다."
public static void applyStyles(Set<Style> styles) {
//...
}
}
핵심 정리
열거할 수 있는 타입을 한데 모아 집합 형태로 사용한다고 해도 비트 필드를 사용할 이유는 없다.
비트 필드 사용하지 마!
EnumSet은 비트 필드 수준의 성능을 제공하고 열거 타입의 장점까지 가져갈 수 있는 멋진 클래스다. 얘를 사용해라.
아직까지 불변 EnumSet을 만들 수는 없지만, 괜찮다.
일단 Collections-unmodifiableSet으로 얘를 감싸서 사용하고 언젠간 자바가 개발해 줄 것이라 믿자.
728x90
'JAVA > Effective Java' 카테고리의 다른 글
item 38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라 (0) | 2022.06.03 |
---|---|
item 37. ordinal 인덱싱 대신 EnumMap을 사용하라 (0) | 2022.06.03 |
item 35. ordinal 메서드 대신 인스턴스 필드를 사용하라 (0) | 2022.05.31 |
item 34. 상수 대신 열거 타입을 사용하라 (0) | 2022.05.31 |
item 33. 타입 안전 이종 컨테이너를 고려하라. (0) | 2022.05.17 |
댓글