본문 바로가기
Backend/Java

[Java] Enum

by unknownomad 2023. 12. 5.

정의

  • Enum이란 Enumeration의 앞 글자로, 열거라는 의미
  • 관련된 상수들의 집합
  • 자바에서는 final 로 String 과 같은 문자열이나 숫자들을 나타내는 기본 자료형의 값 고정 가능
  • = 이렇게 고정된 값이 상수(constant)
  • 어떤 클래스가 상수만으로 작성되어 있으면 반드시 class 로 선언할 필요는 X
  • 이럴 때 클래스로 선언된 부분에 enum 이라 선언 시, 이 객체는 상수의 집합임을 명시적 표현하는 것

배경

  • 기존에는 인터페이스나 클래스 내에서 상수 선언 후 관리해옴
  • 클래스 내에서 선언 시, 네이밍이 겹치거나 불필요하게 상수가 많아지는 단점 있음
  • 인터페이스로 관리 시 위 단점이 일부 상쇄되나, 여전히 IDE의 적극적 지원 부족 및 타입 안정성이 떨어진다는 단점 있었음➡️ 이를 보완하며 나온 것이 Enum

특징

클래스를 상수처럼 사용 가능

  • Enum 도 생성자가 존재하나, Default 생성자는 private 로 되어 있음
  • 이 생성자를 public 으로 변경 시, 컴파일 에러 발생
  • 즉, 다른 클래스나 인터페이스에서의 상수 선언이 클래스 로드 시점에서 생성되듯,
  • Enum 도 생성자가 존재하나, 클래스가 로드되는 시점에서 생성되기에 임의 생성하여 사용할 수 X
public enum  Rank {

    THREE(3, 4_000),
    FOUR(4, 10_000),
    FIVE(5, 30_000);

    private final int match;
    private final int money;
    private int count;

    Rank(int match, int money) {  // Default 생성자는 private 으로 세팅됨
        this.match = match;
        this.money = money;
}

Enum 클래스 구현 , 상수값처럼 유일하게 하나의 인스턴스가 생성되어 사용됨

  • Enum 클래스에서 선언한 상수들은 클래스가 로드될 때 하나의 인스턴스로 생성되어, 싱글톤(Singleton) 형태로 어플리케이션 전체에서 사용됨
  • 싱글톤으로 사용되기에 각각의 Enum 인스턴스에 변수를 추가하여 사용하는 것은 멀티 쓰레드(Multi-Thread) 환경에서 위험할 수 있음
public enum Rank {

    THREE(3, 4_000),
    FOUR(4, 10_000),
    FIVE(5, 30_000);

    private final int match;
    private final int money;
    private int count;

    Rank(int match, int money) {
        this.match = match;
        this.money = money;
    }

    public void plusCount() {
        this.count++;
    }
}
  • 각 인스턴스에 count 라는 변수가 추가되어 있는데, 외부에서 각 등수에 맞게 plusCount() 호출 가능
  • 그러나 멀티 쓰레드 환경에서는 각 인스턴스의 count가 공유되기에 조심해야 함

서로 관련된 상수값들을 모아 Enum 으로 구현 시 유용함

클래스와 같은 문법 체계 따름


상속 지원 X

  • 모든 Enum 은 내부적으로 java.lang.Enum 클래스에 의해 상속됨
  • 자바는 다중 상속 지원 X ➡️ Enum 은 다른 클래스 상속 불가
  • 참고로 toString() 메서드는 상수의 이름을 리턴하도록 구현되어 있음
  • 기존에 상속받고 있는 클래스가 있기에, 다중 상속은 불가하나 다양한 인터페이스 구현 가능
public static void main(String[] args) {
    System.out.println(Rank.FIVE.toString()); // FIVE
}

Enum 내부 API

  • java.lang.Enum 클래스를 기본적으로 상속받기에 몇 가지 메서드를 지원함

 

values()

  • Enum 클래스가 가지고 있는 모든 상수값을 배열의 형태로 리턴
  • 단순히 String 의 형태로 반환하는 것이 아닌, 인스턴스를 반환
  • 즉, Enum 클래스가 가지고 있는 모든 인스턴스를 배열에 담아 반환
public static void main(String[] args) {
    Rank[] values = Rank.values();
    for(int i = 0; i < values.length; i++) {
        System.out.println(values[i]);
    }
    // THREE
    // FOUR
    // FIVE
}

 

valueOf()

  • String 을 파라미터로 받음
  • 인자로 들어온 String 과 일치하는 상수 인스턴스 존재 시, 해당 인스턴스를 반환
  • 단순히 문자열을 반환하는 것이 아닌, 인자로 들어온 문자열과 일치하는 인스턴스를 반환
public static void main(String[] args) {
    System.out.println(Rank.valueOf("THREE")); // THREE
}

 

ordinal()

  • Enum 클래스 내부에 있는 상수들의 인덱스(index)를 리턴
  • 배열과 마찬가지로 0 부터 인덱스 시작
  • 인덱스의 length = 상수의 개수 - 1
 public static void main(String[] args) {
    Rank[] values = Rank.values();
    for(int i = 0; i < values.length; i++) {
        System.out.println(values[i] + " 인덱스는 : " + values[i].ordinal());
    }
    // THREE 인덱스는 : 0
    // FOUR 인덱스는 : 1
    // FIVE 인덱스는 : 2
}

활용

데이터 그룹화 / 관리에 용이

  • 관련되어 있으나 관련성을 표시하기 힘든 형태의 데이터를 한 곳에서 관리 가능
public enum  Winner {

    WINNER("승리", Arrays.asList("kyle","pobi","hello","world")),
    LOSER("패배", Arrays.asList("hodol","dunddoung","rutgo");

    private final String winner;
    private final List<String> list;

    Winner(String winner, List<String> list) {
        this.winner = winner;
        this.list = list;
    }
}

 

  • 상태와 행위를 한 곳에서 관리 가능
public boolean isWinner(String name) {
    return WINNER.list.contains(name);
}

public int getWinnerSize() {
    return WINNER.list.size();
}

 

  • 클래스를 분리하지 않고도 두 데이터의 연관성을 명확하게 보여줌
  • 어떤 수 입력 시, 해당 수와 일치하는 인스턴스를 반환하는 메소드 등
  • 상태와 연관있는 행위도 한 곳에서 관리 가능
public enum Statistic {

    THREE(3, 5000),
    FOUR(4, 50_000),
    FIVE(5, 1_500_000),
    BONUS(5, 3_000_000),
    SIX(6, 2_000_000_000);

    private final int matchingNumbers;
    private final int prize;

    Statistic(int matchingNumbers, int prize) {
        this.matchingNumbers = matchingNumbers;
        this.prize = prize;
    }

    public static Statistic getRank(int numberOfMatch) {
        return Arrays.stream(values())
            .filter(statistic -> statistic.matchingNumbers == numberOfMatch)
            .findFirst()
            .orElseThrow(new IllegalArgumentException("일치하는 번호가 3미만입니다."));
    }

 

Lambda 통한 Enum 사용 극대화

  • 함수형 인터페이스 통해 Enum 의 각 상수 인스턴스도 더 능동적인 프로그래밍 가능
  • 상수와 함수식 정보를 같이 관리 ➡️ 상태와 행위 모두 같은 곳에서 관리 가능
import java.util.function.BiFunction;
    
public enum Operator {

    PLUS("더하기", (a, b) -> (a + b)),
    MINUS("빼기", (a, b) -> (a - b)),
    MULTIPLY("곱하기", (a, b) -> (a * b)),
    DIVIDE("나누기", (a, b) -> (a / b));

    private final String name;
    private final BiFunction<Double, Double, Double> biFunction;

    Operator(String name, BiFunction<Double, Double, Double> biFunction) {
        this.name = name;
        this.biFunction = biFunction;
    }

    public Double calculate(double a, double b) {
        return this.biFunction.apply(a, b);
    }
}

출처

https://velog.io/@kyle/%EC%9E%90%EB%B0%94-Enum-%EA%B8%B0%EB%B3%B8-%EB%B0%8F-%ED%99%9C%EC%9A%A9

'Backend > Java' 카테고리의 다른 글

[Java] Annotation  (0) 2023.12.05
[Java] Exception  (0) 2023.12.05
[Java] Pass by Value vs. Pass by Reference  (0) 2023.12.05
[Java] 기본 자료형 & 참조 자료형  (0) 2023.12.05
[자바의 신] 29장 (ongoing)  (0) 2022.08.31

댓글