1 minute read

비트 필드 열거 상수

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  
      
    //매개 변수 styles는 0개 이상의 STYLE_ 상수를 비트별 OR 한 값이다.  
    public void applyStyle(int styles) {...}  
}

열거한 값들이 집합으로 사용될 경우 예전에는 정수 열거 패턴을 사용했다.

text.applyStyles(STYLE_BOLD | STYLE_ITALIC); // 1 | 2 => 3

이런 식으로 비트 연산을 적용해 여러 상수를 하나의 집합으로 선택할 수 있었고, 이를 비트 필드라 한다.

비트 필트

  • 비트 필드를 사용하면 비트 연산(AND, OR, …)을 사용해 합집합, 교집합 등의 집합 연산을 효율적으로 수행할 수 있다.

하지만…

  • 정수 열거 상수의 단점을 그대로 지니고 있다.
    • type-safe하지 않고, 값 변경되면 다시 컴파일 하는 과정이 필요하다
  • 비트 필드 값이 그대로 출력되면 단순한 정수 열거 상수를 출력할 때보다 의미 파악이 훨씬 어렵다.
  • 비트 필드 하나에 할당된 모든 원소 순회가 까다롭다.
  • 최대 몇 비트가 필요한지, API 작성 시에 미리 예측해 적절한 타입(int, long ...)을 선택해야 한다.
    • 한번 정하고 나면 비트 수 더 늘리기 어려움

EnumSet

  • 열거 타입 상수로 구성된 집합을 효과적으로 표현한다.
  • Set 인터페이스를 완벽히 구현하고 있으며, type-safe하고, 다른 Set 구현체와 함께 사용 가능하다.
  • 비트 벡터로 구현되어 있다.
  • 원소가 64개 이하인 경우, EnumSet 전체를 long 변수 하나로 표현하여 비트 필드에 비견되는 성능을 보여준다.
  • removeAllretailAll과 같은 대량 작업은 비트를 효율적으로 처리 할 수 있는 산술 연산으로 구현해 두었다.
  • 비트를 직접 다룰때 겪는 오류가 발생하지 않을 것이다.
public class Text {  
    public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }  
      
    // 어떤 Set을 넘겨도 되나 EnumSet이 가장 좋다.  
    // 다른 Set 구현체 처리를 위해 이왕이면 Set Interface로 받는게 좋다.  
    public void applyStyles(Set<Style> styles) {...}  
}

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

Leave a comment