[Java] 15. 열거형(이진 데이터 비트 연산자 사용 예제)


Study/Java  2020. 5. 13. 18:33

안녕하세요. 명월입니다.


이 글은 Java의 열거형(이진 데이터 비트 연산자 사용 예제)에 대한 글입니다.


변수를 선언할 때는 값을 넣고 수정할 수 있는 일반 변수와 final 키워드를 사용해서 상수형으로 사용할 수 있습니다.

링크 - [Java] 02. 변수와 상수 선언법, 그리고 원시 데이터형과 클래스 데이터형의 차이


상수형으로 사용하는 경우는 프로그램 상에서 기준이 되는 키 값이던가 비교를 해야하는 값으로 상수를 자주 사용합니다.

// 사람 클래스
class People {
  // 상태
  private int state;
  // 일 추가
  public void addState(int state) {
    // 상태에 추가한다.
    this.state |= state;
  }
  // 출력
  public void print() {
    // 청소했는지 체크
    if ((this.state & 0x01) != 0) {
      // 콘솔 출력
      System.out.println("clean");
    }
    // 공부했는지 체크
    if ((this.state & 0x2) != 0) {
      // 콘솔 출력
      System.out.println("study");
    }
    // 놀았는지 체크
    if ((this.state & 0x4) != 0) {
      // 콘솔 출력
      System.out.println("play");
    }
    // 잤는지 체크
    if ((this.state & 0x8) != 0) {
      // 콘솔 출력
      System.out.println("sleep");
    }
  }
}
public class Example {
  // 상수 선언
  // 청소 0001
  public static final int clean = 0x1;
  // 공부 0010
  public static final int study = 0x2;
  // 놀기 0100
  public static final int play = 0x4;
  // 잠 1000
  public static final int sleep = 0x8;
  // 실행 함수
  public static void main(String... args) {
    // 사람 인스턴스 생성
    People p1 = new People();
    // 청소하고 놀았다.
    p1.addState(clean);
    p1.addState(study);
    // 출력
    p1.print();
  }
}

위 소스는 People이라는 클래스를 사람으로 설정하고 어떤 일을 했는지 추가하는 소스입니다.

여기에 일이라는 것을 기준을 만들기 위해 int형 상수를 네 개 만들었습니다. 그리고 addState에 추가를 하면 People 클래스 안에서는 비트 추가로 일을 추가하게 됩니다.

그리고 print함수로 내역을 출력합니다.


이렇게 작성해도 아무런 문제가 없습니다. 객체 지향의 특성을 위해 일을 Class로 분류해서 추상화, 상속해도 되지만, 이 경우에는 이렇게 작성하는 게 가장 심플합니다.

실제 실무에서도 이렇게 작성하는 경우가 많습니다. 규칙에 따라 프로그램을 만들는 것도 중요합니다만, 그 규칙이 있는 것이 가독성과 관리를 쉽게하기 하기 위한 것이기 때문에, 규칙을 지키지 않고 쉽게 만드는 방법과 보기 좋은 방법이 있으면 그것이 더 좋은 방법일 수도 있습니다.


그런데 시간이 지나고 프로젝트는 점점 커졌을 때, People 클래스의 addState함수를 보니 int형 state가 파라미터로 있습니다.

여기서.. 이 int형이 무엇인지 모르게 됩니다. 함수 내부를 0x1아 아닌 Example.clean으로 설정해 놓았으면 그나마 알 수 있겠지만 그마저도 일반 숫자를 작성해 놓았고 주석도 없습니다.

이러면 문제가 발생하는 것입니다. (퇴사할 때, 후임 개발자 바보 만들기 프로젝트... 이건 나만 아는 코드임... 시전할 때 아주 많이 쓰는 방법입니다. 이러면 안됩니다.)


이를 해결하기 위한게 열거형입니다.

import java.util.ArrayList;
import java.util.List;
// 열거형 타입
enum PeopleState {
  clean, study, play, sleep
}
// 사람 클래스
class People {
  // 상태 리스트
  private List<PeopleState> states = new ArrayList<>();
  // 일 추가
  public void addState(PeopleState state) {
    // 중복은 입력하지 않는다.
    if(!states.contains(state)) {
      // 리스트에 추가
      states.add(state);
    }
  }
  // 출력 함수
  public void print() {
    // 상태 리스트의 값을 가져온다.
    for (int i = 0; i < states.size(); i++) {
      // 열거형은 그대로 출력하면 타입명이 출력된다.
      System.out.println(states.get(i));
    }
  }
}
public class Example {
  // 실행 함수
  public static void main(String... args) {
    // 사람 인스턴스 생성
    People p1 = new People();
    // 청소하고 놀았다.
    p1.addState(PeopleState.clean);
    p1.addState(PeopleState.study);
    // 출력
    p1.print();
  }
}

결과는 같습니다. 그런데 열거형 타입으로 파라미터를 주고 받으니 누가 봐도 addState는 어떤 값이 들어가는지 명확하게 압니다.


참고로 저는 특이하게 위 플래그 값을 2진 데이터로 예제를 설명했습니다. 보통은 저렇게 이진 데이터 안 넣고 열거형 예제의 열거형 대신에 일반 int나 String 값으로 하는 경우가 있습니다.

2진 데이터 비교하는 방법은 꽤 많은 플래그를 비교 계산할 때, 빠른 속도로 처리할 수 있습니다. 실제 업무에서도 저런 2진 데이터 비교 코드가 많이 있습니다.

열거형을 사용한다고 느려지고 성능이 저하되는 건 아니지만, List를 사용하고 비교 처리가 있으면 비트 연산자 처리가 안 되고 equals를 사용하는 경우가 많기 때문에 아무래도 이진 데이터를 비트 연산자로 비교하는 게 아주 조금 더 빨리 처리하지 않을까 싶습니다.

그래서 참고 사항으로 제가 예제로 만들어 봤습니다.


여기까지 Java의 열거형(이진 데이터 비트 연산자 사용 예제)에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.