[Java] enum

 

우아한테크코스 6기 프리코스 중 3주차 과제를 통해 enum을 어떻게 객체로 활용할지에 대한 고민이 많았다. 4주차에도 이를 확실히 활용할 수 있도록 자세히 파헤쳐보려한다.

 

✔️ enum이란?

Enum은 Enumeration의 약자다. 즉, 열거형은 요소, 멤버라 불리는 명명된 값의 집합을 이루는 자료형이다. 정해져있는 한정된 데이터 묶음을 열거형 타입인 Enum으로 묶어주면 보다 구조적으로 프로그래밍 할 수 있다. Enum의 장점은 다음과 같다.

 

1. 문자열과 비교해 IDE의 적극적인 지원을 받을 수 있다.

  • 자동완성, 오타검증, 테스트 리팩토링 등

2. 허용 가능한 값들을 제한하여 유형 안전(type safe)을 제공한다.

3. 리팩토링 시 변경 범위가 최소화된다.

  • 내용의 추가가 필요하더라도, Enum 코드 이외에 수정할 필요가 없다.

4. 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 나타낼 수 있다.

 


 

✔️ enum 메서드 종류

메서드 설명 리턴 타입
name() 열거 객체의 문자열을 리턴 String
ordinal() 열거 객체의 순번(0부터 시작)을 리턴 int
compareTo() 열거 객체를 비교해서 순번 차이를 리턴 int
valueOf(String name) 문자열을 입력받아서 일치하는 열거 객체를 리턴 enum
values() 모든 열거 객체들을 배열로 리턴 enum[]

 

name() 메서드

Fruit f = Fruit.APPLE;

// 열거 객체의 문자열 리턴
String fruitName = f.name();
System.out.println(fruitName); // Apple

 

ordinal() 메서드

Fruit f = Fruit.APPLE;

// 열거 객체의 순번 리턴
int fruitNumber = f.ordinal();
System.out.println(fruitNumber); // 1

 

compareTo() 메서드

// 열거 객체를 비교해서 순번 차이를 리턴 (시작점을 어느 열거 객체의 기준으로 몇번째 위치하는지)
Fruit f1 = Fruit.APPLE; // 1
Fruit f2 = Fruit.BANANA; // 2

// 열거 객체가 매개값의 열거 객체보다 순번이 빠르다 → 음수를 리턴
int compare1 = f1.compareTo(f2); // BANANA를 기준으로 APPLE 위치 (2에서 1가 되기 위한 값)
System.out.println(compare1); // -1

// 열거 객체가 매개값의 열거 객체보다 순번이 늦다 → 양수를 리턴
int compare2 = f2.compareTo(f1); // APPLE 기준으로 BANANA 위치 (1에서 2가 되기 위한 값)
System.out.println(compare2); // 1

 

valueOf(String name) 메서드

// 문자열을 입력받아서 일치하는 열거 객체를 리턴
Fruit f3 = Fruit.valueOf("MANGO"); // f3 변수는 Fruit.MANGO 열거 객체를 참조하게 됨
System.out.println(f3); // MANGO

 

values() 메서드

// 모든 열거 객체들을 배열로 리턴
Fruit[] f4 = Fruit.values();

System.out.println(Arrays.toString(f4)); // [APPLE, BANANA, MANGO]

for (Fruit type : Fruit.values()) { // 열거 순회
    System.out.println(type);  // 순서대로 열거 객체 출력
}

 


 

✔️ enum 매핑

enum은 데이터 그룹화 및 관리에 용이하다. 즉, 서로 관련되어있는 데이터들을 한 클래스 내에서 관리할 수 있다. 다음은 3주차 과제 로또 게임의 일부 코드이다.

public enum WinningStatistics {
    FIRST(6, 2_000_000_000, false, "\n6개 일치 (2,000,000,000원) - "),
    SECOND(5, 30_000_000, true, "\n5개 일치, 보너스 볼 일치 (30,000,000원) - "),
    THIRD(5, 1_500_000, false, "\n5개 일치 (1,500,000원) - "),
    FOURTH(4, 50_000, false, "\n4개 일치 (50,000원) - "),
    FIFTH(3, 5_000, false, "3개 일치 (5,000원) - "),
    NOTHING(0, 0, false, "");

    private final int matchCount;
    private final int reward;
    private final boolean isContainBonus;
    private final String message;

    WinningStatistics(int matchCount, int reward, boolean isContainBonus, String message) {
        this.matchCount = matchCount;
        this.reward = reward;
        this.isContainBonus = isContainBonus;
        this.message = message;
    }
}

 

 


 

✔️ enum 확장

enum 매핑 기능을 확장하여 enum을 단순히 상수 값을 넘어서 상수 메서드로서 사용할 수 있다.

 

위 코드에서 enum 매핑은 클래스 필드와 생성자를 정의해서 상수의 매개변수 값을 필드에 저장하고 인스턴스화 함으로써 고유한 상수 객체로서 활용했다.

 

여기서 더 나아가 추상 메서드를 정의해 각 상수마다 익명 클래스(프로그램에서 일시적으로 한 번만 사용되고 버려지는 객체)처럼 메서드 재정의를 통해 각 상수마다 다른 역할을 하는 메서드를 갖게 되는 원리이다.

 

enum Operation {
    PLUS("+") {
        public double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS("-") {
        public double apply(double x, double y) {
            return x - y;
        }
    },
    MULTI("*") {
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/") {
        public double apply(double x, double y) {
            return x / y;
        }
    };

    // 클래스 생성자와 멤버
    private final String symbol;
    Operation(String symbol) {
        this.symbol = symbol;
    }

    // toString을 재정의하여 열거 객체의 매핑된 문자열을 반환하도록
    @Override
    public String toString() {
        return symbol;
    }

    // 열거 객체의 메소드에 사용될 추상 메소드 정의
    public abstract double apply(double x, double y);
}

 

enum은 상태와 행위 모두 한 곳에서 관리 가능

이처럼 enum은 단순히 상수 표현식을 넘어서 동작, 행위를 수행하는 상수로서도 응용 확장이 가능하다. 상수 상태와 행위를 한 곳에서 관리할 수 있는 것이다.

 

예를 들어 각 상수를 특정 데이터와 연결짓거나, 상수마다 다르게 동작해야하는 로직이 필요할 때 일반적으로 if문 또는 switch문으로 구현하기 마련이다. 그러나 이러한 코드 구성은 값(상태)과 메서드(행위)가 어떤 관계가 있는지 파악하기 어렵다. 하지만 enum을 이용하면 상태와 행위를 한 눈에 파악할 수 있다. 즉, 객체지향적으로 코드를 패턴화하여 유지보수하기 용이하게 만들 수 있다.

 

enum Operation {
    PLUS("+") {
        public double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS("-") {
        public double apply(double x, double y) {
            return x - y;
        }
    },
    MULTI("*") {
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/") {
        public double apply(double x, double y) {
            return x / y;
        }
    };
}

 

enum에 람다식 사용

enum은 람다식을 통해 위 코드를 더욱 깔끔하게 만들 수 있다.

 

enum Operation {
    PLUS("+", (x, y) -> x + y),
    MINUS("-", (x, y) -> x - y),
    TIMES("*", (x, y) -> x * y),
    DIVIDE("/", (x, y) -> x / y);

	private final DoubleBinaryOperator op; // 람다식을 저장할 필드
    private final String symbol;
    
    Operation(DoubleBinaryOperator op, String symbol) {
    	this.op = op;
        this.symbol = symbol;
    }

    // toString을 재정의하여 열거 객체의 매핑된 문자열을 반환하도록
    @Override
    public String toString() {
        return symbol;
    }

    // 열거 객체의 메소드에 사용될 추상 메소드 정의
    public double apply(double x, double y) {
    	return op.apllyAsDouble(x, y);
    }
}

 

 

위 내용은 다음 블로그들을 참고하였습니다.

https://tecoble.techcourse.co.kr/post/2020-07-29-dont-use-else/

 

else 예약어를 쓰지 않는다

The ThoughtWorks Anthology의 더 나은 소프트웨어를 향한 9단계: 객체지향 생활 체조 중 규칙…

tecoble.techcourse.co.kr

https://techblog.woowahan.com/2527/

 

Java Enum 활용기 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요? 우아한 형제들에서 결제/정산 시스템을 개발하고 있는 이동욱입니다. 이번 사내 블로그 포스팅 주제로 저는 Java Enum 활용 경험을 선택하였습니다. 이전에 개인 블로그에 E

techblog.woowahan.com

https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EC%97%B4%EA%B1%B0%ED%98%95Enum-%ED%83%80%EC%9E%85-%EB%AC%B8%EB%B2%95-%ED%99%9C%EC%9A%A9-%EC%A0%95%EB%A6%AC

 

☕ 자바 Enum 열거형 타입 문법 & 응용 💯 정리

Enum 열거 타입 먼저 Enum은 "Enumeration"의 약자다. Enumeration은 "열거, 목록, 일람표" 라는 뜻을 가지고 있으며, 보통 한글로는 열거형이라고 부른다. 즉, 열거형(enum)은 요소, 멤버라 불리는 명명된 값

inpa.tistory.com

 

'☕️ Java' 카테고리의 다른 글

[Java] Stream  (4) 2023.11.09
[Java] 일급 컬렉션  (2) 2023.10.26