Java

[Effective Java] 6-1. 열거 타입과 애노테이션

noahkim_ 2024. 12. 30. 22:22

조슈아 블로크 님의 "Effective Java" 책을 정리한 포스팅 입니다.


1. int 상수 대신 열거 타입을 사용하라

정수 열거 타입

public final class IntEnumPattern {
    public static final int APPLE_FUJI = 0;
    public static final int APPLE_PIPPIN = 1;
    public static final int APPLE_GRANNY_SMITH = 2;

    public static final int ORANGE_NAVEL = 0;
    public static final int ORANGE_TEMPLE = 1;
    public static final int ORANGE_BLOOD = 2;
}
  • 타입 안정적이지 않음
  • 별도 이름공간 없음
  • 변경되변 클라이언트 코드도 변경되어야 함
  • 순회하기 어려움
  • 몇개인지 알기 어려움

 

Enum

  • 일정 개수의 상수 값을 정의한 다음, 그 외의 값은 허용하지 않는 타입

 

완전한 형태의 클래스
// 인터페이스 정의
interface Displayable {
    String display();
}

// Enum 정의
enum Fruit implements Displayable {
    APPLE("Red", 95) {
        @Override
        public String specialFeature() {
            return "Keeps doctors away!";
        }
    },
    ORANGE("Orange", 62) {
        @Override
        public String specialFeature() {
            return "Rich in Vitamin C!";
        }
    },
    BANANA("Yellow", 105) {
        @Override
        public String specialFeature() {
            return "Great for energy boost!";
        }
    };

    // 필드
    private final String color;
    private final int calories;

    // 생성자
    Fruit(String color, int calories) {
        this.color = color;
        this.calories = calories;
    }

    // 일반 메서드
    public String getColor() { return color; }
    public int getCalories() { return calories; }
        
    // 추상 메서드: 각 열거 상수가 고유한 동작을 제공
    public abstract String specialFeature();

    // 인터페이스 메서드 구현
    @Override
    public String display() {
        return String.format("%s: Color=%s, Calories=%d", this.name(), color, calories);
    }
}
  • 상수 하나당 자신의 인스턴스를 하나씩 만들어, public static final 필드로 공개
  • 각자의 이름공간이 있음
  • 임의의 필드나 함수 추가 가능 (다른 상수끼리 공유 X)
  • 인터페이스 구현 가능
  • 컴파일타임 안전성 제공
  • 생성자 비공개 (확장 불가)

 

2. ordinal 메서드 대신 인스턴스 필드를 사용하라

ordinal 메서드

  • 열거 타입에서 몇번째 인스턴스인지를 반환하는 메서드
  • 열거타입 기반의 범용 자료구조에 쓸 목적으로 설계됨
  • 유지보수 하기 어려움

 

ordinal 관련 값은 인스턴스 필드에 저장하기

public enum Ensemble {
    SOLO(1), DUET(2);
    
    private final int numberOfMusicians;
}

 

 

3. 비트 필드 대신 EnumSet을 사용하라

비트 필드

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

    public void applyStyles(int styles) {
        System.out.println("Applying styles: " + styles);
    }

    public static void main(String[] args) {
        Text text = new Text();
        text.applyStyles(STYLE_BOLD | STYLE_ITALIC); // 비트 연산 사용
    }
}
  • 여러 상수 값을 조합해서 사용할 수 있도록 비트를 활용한 방식

 

단점
  • 타입 안전성 부족
  • 가독성 낮음
  • 확장성 부족

 

 

EnumSet

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

    public void applyStyles(Set<Style> styles) {
        System.out.println("Applying styles: " + styles);
    }

    public static void main(String[] args) {
        Text text = new Text();
        text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC)); // EnumSet 사용
    }
}
  • 열거 타입 상수의 값으로 구성된 집합을 효과적으로 표현해줌
  • Set 인터페이스 구현
  • 내부는 비트 벡터로 구현됨

 

장점
  • 타입 안전