[Effective Java] 아이템 36 : 비트 필드 대신 EnumSet을 사용하라

Loopy·2022년 8월 19일
0

이펙티브 자바

목록 보기
35/76
post-thumbnail
post-custom-banner

☁️ 비트 필드 열거 상수

열거한 값들이 단독이 아닌 집합으로 사용되어야 할 경우, EnumSet이 나오기 전에는 각 상수에 서로 다른 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;  //8
    
    public void applyStyles(int styles) {
        System.out.printf("Applying styles %s to text%n", styles);
   }
}

여러 상수를 하나의 집합으로 모을려면, 아래와 같이 비트 연산자 OR을 사용하면 된다. 이렇게 되면 비트 필드로 표현되는 하나의 집합을 생성할 수 있다.

text.applyStyles(STYLE_BOLD | STLYE_ITALIC); // 0001 OR 0010 = 0011

🫧 비트마스킹
비트 필드를 사용하여 비트별 연산을 통해 집합 연산을 수행하는 것을 의미한다.

비트 필드 단점

  1. 예전에 보았던 정수 열거 상수의 단점을 그대로 지닌다.(타입 안전성 X, 이름 공간 충돌 등)
  2. 비트 값 필드가 그대로 출력되었을 때 해석하기 어렵다.
  3. 최대 몇 비트가 필요한지 예측해서 적절한 타입(int/long)을 선택해야 한다.
public static void main(String[] args) {
     Text text = new Text();
     text.applyStyles(Text.STYLE_BOLD | Text.STYLE_ITALIC);
}

☁️ EnumSet

java.util 패키지의 EnumSet 클래스열거 타입 상수의 값으로 구성된 집합을 효과적으로 표현해준다.

Set 인터페이스 자체를 구현하고 있기 때문에 타입 안전하며, 출력했을 때도 알아보기 쉽게 정보를 담고 있다는 장점이 있다.

🫧 참고
EnumSet 은 비트 벡터로 구현되었기 때문에, 원소가 64 개 이하라면 EnumSet 전체를 long 변수 하나로 표현하여 비트 필드에 비견되는 성능을 보여준다.

class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
    private long elements = 0L;   // 비트 필드
 }
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
    private long elements[];      
}

앞에서의 코드를 EnumSet 으로 수정해보자.

public class Text {
    public enum Style {BOLD, ITALIC, UNDERLINE, STRIKETHROUGH}

    public void applyStyles(Set<Style> styles) {
        System.out.printf("Applying styles %s to text%n",
                Objects.requireNonNull(styles));
    }
}

public static void main(String[] args) {
     Text text = new Text();
     text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
}

EnumSet 단점

EnumSet 은 불변이 불가능하다.
하지만 Collections.unmodifiableSet 으로 EnumSet을 감싸, 집합을 수정하려 하거든 예외를 터트리게 하는 방식으로 사용할 수 있는 방안은 존재한다.

📚 핵심 정리
열거할 수 있는 타입을 한데 모아 집합 형태로 사용한다고 해도 비트 필드를 사용할 이유는 없다. EnumSet 클래스가 비트 필드 수준의 명료함과 성능을 제공하고, 열거 타입의 장점까지 주기 때문이다.

profile
개인용으로 공부하는 공간입니다. 잘못된 부분은 피드백 부탁드립니다!
post-custom-banner

0개의 댓글