JAVA/Effective Java

item 36. 비트 필드 대신 EnumSet을 사용하라

Garonguri 2022. 5. 31. 16:01
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