[교재 EffectiveJava] 아이템 36. 비트 필드 대신 EnumSet을 사용하라

반응형
728x90
반응형

비트 필드 열거 상수 

열거한 값들이 주로 집합으로 사용될 경우 예전에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용해왔다.

 

오래된 기법
package com.java.effective.item36;

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_STRIKERTHROUGH = 1 << 3; // 8

    // 매개변수 styles 는 0개 이상의 STYLE_ 상수를 비트별 OR 한 값이다.
    public void applyStyles(int style) {

    }
}

 

아래의 식으로 비트별 OR을 사용해 여러 상수를 하나의 집합으로 모을 수 있으며, 이렇게 만들어진 집합을 비트 필드라 한다.

text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

 

비트 필드를 사용하면 비트별 연산을 사용해 합집합과 교집합과 같은 집합 연산을 효율적으로 수행할 수 있다. 하지만 비트 필드는 정수 열거 상수의 단점을 그대로 지닌다. 비트 필드 값이 그대로 출력되면 단순한 정수 열거 상수를 출력할 때보다 해석하기 훨씬 어렵다. 

 

비트 필드를 사용해야할때, 사용하려고할때 이를 사용하지 말고 더 나은 방법인 java.util 클래스의 EnumSet 을 사용하자.

 

 

EnumSet

EnumSet.java
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
    implements Cloneable, java.io.Serializable
{
    ...
}

public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
    ...
}

public interface Set<E> extends Collection<E> {
   ...
}

EnumSet 클래스는 열거 타입 상수의 값으로 구성된 집합을 효과적으로 표현해준다. Set 인터페이스를 완벽히 구현하며, 타입 안전하고, 다른 어떤 Set 구현체와도 함께 사용할 수 있다. 하지만 EnumSet의 내부는 비트 벡터로 되어있어있어, 대부분의 경우에 EnumSet 전체를 long 변수 하나로 표현하여 비트 필드에 비견되는 성능을 보여준다. 

package com.java.effective.item36;

import java.util.Set;

public class TextEnumSet {
    public enum Style {
        BOLD,
        ITALIC,
        UNDERLINE,
        STRIKETHROUGH
    }
    
    // 어떤 Set을 넘겨도 되나, EnumSet 이 가장 좋다.
    public void applyStyles(Set<Style> styles) {
        
    }
}

 

클라이언트
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));

 

applyStyles 메서드가 EnumSet<Style>이 아닌 Set<Style>을 받은 이유를 생각해보자.

public interface Set<E> extends Collection<E> {
    ...
}

 

모든 클라이언트가 EnumSet을 건네리라 짐작되는 상황이라도 이왕이면 인터페이스로 받아서 어떤 Set 구현체를 넘기더라도 처리할 수 있게하자.

 

 

반응형

Designed by JB FACTORY