[이펙티브 자바] Item36 - 비트 필드 대신 EnumSet을 사용하라

이성훈·2022년 6월 18일
0

이펙티브 자바

목록 보기
16/17
post-thumbnail

<"비트 필드 대신 EnumSet을 사용하라">


이번 아이템에서는 비트 필드와 EnumSet을 비교해보며 EnumSet의 장점에 대해서 알아본다.





#   비트 필드


열거타입으로 지정된 원소들이 집합의 형태로 사용되는 경우가 있다.


<Comment.>

  • 첫 문장부터 의미가 매우 난해하지만 예컨대 이런거다.
  • 문서를 작성하는 프로그램을 사용하다 보면 글자의 형태를 여러가지로 지정할 수 있다.
  • 폰트, 기울임 정도, 밑줄, 굵기 등이 있을 것이다.
  • 위 원소들은 글자의 형태를 구성하지만 서로가 독립적이다.
  • 그렇기에 각 원소를 상수 타입으로 구성하여 글자 형태를 구성하는 열거 클래스를 만들 수 있다.

위와 같은 경우에, 전통적으로 사용하는 방식은 각 상수에 2의 거듭제곱 값을 배정하는 정수 열거 패턴(Item34)을 사용했다.

2의 거듭제곱 값을 2진수 형태로 풀어서 배정하면,
각 상수들은 서로 겹치지 않는 유니크 값을 가질 수 있게되며 서로 Join도 가능해진다.


다음의 예시를 보자.

public class Text {
    public static final int STYLE_BOLD = 1 << 0;        	//==0001  = 1
    public static final int STYLE_ITALIC = 1 << 1;			//==0010  = 2
    public static final int STYLE_UNDERLINE = 1 << 2;		//==0100  = 4
    public static final int STYLE_STRIKETHROUGH = 1 << 3;	//==1000  = 8

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

위의 예시를 보면 글자 스타일을 구성하는 상수가 각자 2의 거듭제곱 형태의 값을 배정받았다.


여기까지는 무슨 말인지 알겠으나, 가장 처음에 나왔던
"원소들이 집합의 형태로 사용되는 경우" 라는게 잘 이해가 가지 않는다.


이는 위를 사용하는 클라이언트 코드를 보면 쉽게 이해가 된다.

    public static void main(String[] args) {
        Text text = new Text();
        text.applyStyles(STYLE_BOLD | STYLE_ITALIC);
    }
}

STYLE_BOLD와 STYLE_ITALIC을 OR(합집합) 시켜서 메서드를 호출하고 있다.

글자 스타일은 굵게, 또 기울여서 라는 의미인 것을 직관적으로 알 수 있다.


STYLE_BOLD는 0001, STYLE_ITALIC은 0010으로, 합집합 시키면 0011이 된다.

이 또한 다른 것들과 겹치지 않는 유니크 한 값이 되기에 이렇게 정수 열거패턴을 사용했다는 의미가 되겠다.
(전통적으로..)


이제 배경 이해는 된 것 같다.

다만 이런 전통적인 방식이 단점을 가지기에 문제가 되는 것이다.


<비트 필드 방식의 단점>

  • 해석하기가 어렵다.
    위의 예시만 봐도, 숫자 3이 글자를 기울이고 굵게 해달라는 의미인걸 누가 알 수 있겠는가.
  • 최대 몇 비트가 필요할 지 처음부터 예상하고 자료형을 지정해야 한다.
    위의 글자 스타일의 경우 4개만 있었지만, 일반적인 범주에서는 모든 경우의 수를 다 알지 못하기 때문에 리스크가 커진다.
  • 경우의 수가 너무 많은 경우, 감당이 안된다.
    예를 들어 long 이더라도 64비트만 지원하기 때문에 경우의 수가 65가지 이상이면 감당 불가인 것이다.

이런 문제를 해결하기 위한 방안이 바로 EnumSet이다.



#   EnumSet


위의 정수 열거 패턴의 예시를 EnumSet을 사용한 것으로 바꾸어보면 다음과 같다.


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

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


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

딱히 설명이 필요없는 깔끔한 형태다.

이렇게 보면 어째서 정수 열거 패턴을 과거에 사용해왔는지 모를 정도이다.

다만 Enumerate라는 자료형 자체가 프로그래밍 언어의 시작과 함께 해온 것이 아니라는걸 감안해보면 충분히 그럴만 하다.


애초에 비트 연산 자체가 약간 전통적인 C 스타일인것 같기도 하다.

추가적으로, applyStyles에서 파라미터가 Set

어차피 클라이언트 코드에서 EnumSet으로 넘길텐데 EnumSet

그렇다고 하더라도, 보다 상위 개념인 인터페이스 형태로 받는게 더 안전하기 때문이다.



여기까지 비트 필드와 EnumSet에 대한 내용이였다.

profile
IT 지식 공간

0개의 댓글