제 홈페이지의 모든 글은 anti-nhn license에 따릅니다.



EnumSet

본 내용은 Paleys.com 에 있는 Joshua bloch의 Effective java reload 동영상을 바탕으로 쓴 글입니다.

EnumSet은 bit 필드를 대신하기 위해서 나온 것입니다.

다음과 같은 코드를 생각해봅시다.

public class Text{
    public static final int STYLE_BOLD = 1;
    public static final int STYLE_ITALIC = 2;
    public static final int STYLE_UNDERLINE = 4;
    public static final int STYLE_STRIKETHROUGH = 8;

    // 인자는 STYLE_ 의 조합으로 이루어진 데이터.
    public void applyStyles(int styles){ ... }
}

이 것을 사용하는 클라이언트 코드는

text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

와 같이 됩니다.

일반적인 list나 set에 비해 bit 연산으로 처리하면 좋은 점은 속도가 월등히 빠르다는 것입니다.

그러나 여기에는 몇가지 문제 점들이 있습니다.
  1. type이 보장되지 않습니다. BOLD는 1이지만, 1이 반드시 BOLD의 의미로 쓰인다는 보장이 없습니다.
  2. 1에 연관되는 문제로 STYLE_과 같은 식의 prefix가 없으면 보기가 졸라 헤깔립니다. 또한 STYLE에 관련되지 않은 다른 종류의 상수들이 왕창 있을 경우 더욱 복잡해집니다. 예를 들어 FONT_SMALL = 1; 와 같은 것이 있다면, STYLE_BOLD와 값은 같지만 의미하는 바가 전혀 다르며, 전적으로 prefix에 의존해서 구분하는 수 밖에 없게 됩니다.
  3. 안전하지 못합니다. java의 constant는 값을 컴파일 시점에 값을 복사합니다. 따라서 api에서 코드를 바꿀 경우 클라이언트 코드가 정상적으로 작동하지 않습니다.
    ex>
    public class Constants {
        public static final String name = "홍길동";
    }
    public class AnotherClass{
         String a =  Constants.name;
    }

    이것은 컴파일 시점에 
    String a= "홍길동";
    으로 바뀝니다. 따라서 Constants 클래스의 name값을 바꾸고 Constants만 다시 컴파일할 경우 AnotherClass의 a 는 여전히 "홍길동"입니다.
  4. 값을 찍었을 때 무슨 뜻인지 직관적이지 않습니다. 예를들어, 3은 BOLD와 ITALIC의 의미가 됩니다.
  5. 값을 iteration 을 돌리기가 쉽지 않습니다. 비트 단위로 하나씩 자리수를 변경시켜가며 값이 있는지 없는 지 체크해야 합니다.
  6. 갯수가 너무 많을 경우 커버할 수 없습니다. int가 아니라 long으로 하더라도 그 범위를 넘어가는 것은 표현할 수 없습니다.

이에 대한 해결책으로 EnumSet 이 있습니다. 위의 예제를 enum과 EnumSet을 이용하여 다시 쓰면 아래와 같이 됩니다.

public class Text{
    public enum Style{
        BOLD, ITALIC, UNDERLINE, STRIKETHROUGH
    }
    //어떤 종류의 Set의 구현체이건 다 들어갈 수 있지만, EnumSet이 젤 좋다.
    public void applyStyles(Set<Style> styles){ ... }
}

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

이렇게 하면 위에서 열거한 모든 문제들이 해결됩니다.

  1. 타입이 안전해 졌습니다.
  2. enum 자체가 name space의 역할을 합니다.
  3. 상수와는 달리 동적으로 클라이언트 코드에 링크가 되기 때문에, api를 바꾸어도 클라이언트에 지장을 주지 않습니다.
  4. 이름이 주어지기 때문에 읽기가 쉽습니다.
  5. for(Style style : styles) 와 같이 iteration이 쉬워집니다.
  6. 갯수 제한도 없습니다.

위에서 열거한 점들은 bit 연산을 그냥 Set으로 바꿨을 때도 다 해결되는 문제들입니다. 그러면 EnumSet이 더 좋은 이유를 알아봅시다.

EnumSet은 contains 등의 메쏘드에서 Enum.ordinal() 등을 사용하여 비트 연산과 속도 차이가 거의 나지 않습니다. 따라서 HashSet보다 더 빠릅니다.
EnumSet의 static 메쏘드인 of를 사용하게 되면, 그 enum의 크기(element의 갯수)에 따라 JumboEnumSet과 RegularEnumSet (둘다 abstract class인 EnumSet을 상속받음) 중에 선택되어 객체를 생성합니다. (EnumSet.of() 는 factory method란 뜻이죠.)

클라이언트 코드를 HashSet으로 바꾸게 되면,
Set<Style> styles = new HashSet<Style>();
styles.add(Style.BOLD);
styles.add(Style.ITALIC);
text.applyStyles(styles);
와 같이 번거롭게 됩니다. 물론 좀 줄이면

text.applyStyles( new HashSet<Style>(){ { add(Style.BOLD); add(Style.ITALIC);}});

과 같이 되긴 합니다만, EnumSet.of 를 쓰는 코드에 비하면 역시나 번거롭기 짝이 없습니다.

이 글과 관련있는 글을 자동검색한 결과입니다 [?]

by 삼실청년 | 2009/02/03 22:47 | 컴터질~ | 트랙백 | 덧글(6)

트랙백 주소 : http://iilii.egloos.com/tb/4835182
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 용식 at 2009/02/04 13:44
위 포스트보다 이 포스트가 왠지 더 관심이 많이 가네요~
비트 연산에 대한 것도 그렇구요..

오픈소스에 보면 비트연산을 해놓은 부분이 있기도 하더라구요..개인적으로 비트연산 코드는 본적이 거의 없어서.. 잘 모르거든요..

공부 좀 해봐야 겠네요.. ^^

감사합니다.~
Commented by 삼실청년 at 2009/02/04 16:53
비트 연산은 2진수 표현법입니다.
위의 예제를 보면 2진수로 표현했을 때 (대략 4자리만..)
BOLD = 0001
ITALIC = 0010
UNDERLINE = 0100
STRIKE = 1000

입니다. 각각은 1개의 1과 나머지는 전부 0인 수로 표현이 되는거죠.

BOLD | ITALIC 과 같이 | 로 연결을 시키면 각 자리수 별로 or 처리가 됩니다. 즉 0011 이 되지요. (이게 10진수로는 3이죠. 10진수를 2진수로 바꿔서 자리수 별로 각각의 의미를 찾아내야 합니다. 가독성이 떨어진다는 의미가 이겁니다.)

넘겨 받은 인자를 arg라고 했을 때,
if( ( ITALIC & arg ) == ITALIC) 와 같이 체크하면 ITALIC이 있는지 알 수 있습니다. &는 and의 의미입니다.

일반적으로는 shift 연산을 쓰는 것 같더군요.
저두 전공자가 아니라 비트 연산은 잘 모릅니다만, 대략 아는 선에서 말씀드리면 이정돕니다.
Commented by 용식 at 2009/02/05 11:16
예전에 배웠던 기억이 새록새록 나네요.
(대학 다니면서 분명 배웠던 것들인데..군대 다녀오고 뇌 포맷이 된듯합니다 ㅠㅠ)

검색엔진에서도 저런 기법이 사용되는 것으로 알고 있는데..
가독성이 많이 떨어짐에도 불구하고 사용하는 이유는 말씀하신대로
속도에서 많은 이득이 있기 때문인가 보네요. ^^

감사합니다!
Commented by 삼실청년 at 2009/02/05 18:24
저런 방식이 클라이언트 코드를 간결하게 해주는 건 있죠. 가독성도 좋고.
Commented by 용식 at 2009/02/05 23:08
그렇군요..
제게 익숙하지 않아서 마냥 가독성이 좋지 않은 것 같았는데
다시 보면 또 그렇지만도 않은거 같네요.

아무튼 굉장히 흥미가 가는 내용입니다.^^
Commented by 삼실청년 at 2009/02/08 00:53
세상에 참 똑똑한 사람들 많은 것 같습니다. 흥미로운 아이디어도 많고, 그걸 구현한 것들도 놀랍습니다.
똑똑한 사람들이 만든 것들 좀 더 찾아봐야겠습니다.

:         :

:

비공개 덧글

◀ 이전 페이지          다음 페이지 ▶