[Java] Enum 클래스

Yujeong·2024년 5월 29일
0

Java

목록 보기
11/22
post-thumbnail

열거형이란?

열거형(enums)은 enumeration의 줄임말로, 어떤 항목을 나열하는 것을 의미한다.
서로 관련된 상수를 편리하게 선언하기 위한 것으로, 여러 상수를 정의할 때 사용한다.

열거형이 생겨난 이유

열거형(Enum Type)을 제대로 이해하기 위해서는 열거형이 생겨난 이유를 아는 게 좋다.

1. 문자열
문자열을 사용해서 상품 카테고리와 가격을 입력하면 할인 금액을 계산해주는 클래스를 만들어 보겠다.

public class DiscountService {
	public int discount(String category, int price) {
    int discountPercent = 0;
    
    if (category.equals("ELECTRONICS")) {
    	discountPercent = 10;
    } else if (category.equals("CLOTHING")) {
    	discountPercent = 20;
    } else if (category.equals("BOOKS")) {
    	discountPercent = 15;
    } else {
    	System.out.println("category + "는 할인되지 않습니다.");
    }
    
    return price * discountPercent / 100;
}
public class StringCategoryMain {
	public static void main(String[] args) {
    	int price = 100_000;
        
        DiscountService discountService = new DiscountService();
        int electronics = discountService.discount("ELECTRONICS", price);
        System.out.println("Electronics의 할인된 금액: " + electronics); //10000
    }
}

이렇게 사용하면 문제가 생긴다.
예를 들어, "ELECTRONICS" 대신에 "electronics"로 잘못 입력한다면 할인되지 않는다.

  • 타입 안정성 부족
    - 오타가 발생하기 쉬움
    - 유효하지 않은 값이 입력될 수 있음
    → 컴파일 시 오류 감지 불가능하여 디버깅이 어려워짐
  • 데이터 일관성 떨어짐
    - 다양한 형식으로 문자열을 입력할 수 있음

2. 상수
다음의 코드처럼 "상수를 이용하면 되지 않을까?"라는 생각이 들 것이다.

public class StringCategory {
	public static final String ELECTRONICS = "ELECTRONICS";
    public static final String CLOTHING = "CLOTHING";
    public static final String BOOKS = "BOOKS";
}
public class DiscountService {
	public int discount(String category, int price) {
    int discountPercent = 0;
    
    if (category.equals(StringCategory.ELECTRONICS)) {
    	discountPercent = 10;
    } else if (category.equals(StringCategory.CLOTHING)) {
    	discountPercent = 20;
    } else if (category.equals(StringCategory.BOOKS)) {
    	discountPercent = 15;
    } else {
    	System.out.println("category + "는 할인되지 않습니다.");
    }
    
    return price * discountPercent / 100;
}
public class StringCategoryMain {
	public static void main(String[] args) {
    	int price = 100_000;
        
        DiscountService discountService = new DiscountService();
        int electronics = discountService.discount(StringCategory.ELECTRONICS, price);
        System.out.println("Electronics의 할인된 금액: " + electronics); //10000
    }
}

문자열 상수를 사용함으로써 코드가 개선되었다.

  • 코드가 명확해짐
  • 상수의 이름을 잘못 입력하면 컴파일 시점에 오류 발생

그럼에도 불구하고, 해결되지 않은 문제가 있다. 꼭 문자열 상수가 아니어도 상관없다는 것이다.
예를 들어, 문자열 상수를 사용하지 않고, 카테고리에 없는 "FURNITURE"라고 입력할 수도 있다.

  • String 타입이면 입력 가능함

타입에 안전한 열거형 패턴

자바의 열거형은 "타입에 안전한 열거형(Type-Safe Enum)"이기 때문에 실제 값이 같아도 타입이 다르면 컴파일 에러가 발생한다. 그러므로, 나열한 항목만 사용할 수 있다.

위의 코드를 타입에 안전한 열거형 패턴으로 리팩토링 해보자.

  • 새로운 객체 생성
  • 참조값으로 비교
  • private 생성자 추가
public class ClassCategory {
	public static final ClassCategory ELECTRONICS = new ClassCategory();
    public static final ClassCategory CLOTHING = new ClassCategory();
    public static final ClassCategory BOOKS = new ClassCategory();
    
    private ClassCategory() {}
}
public class DiscountService {
	public int discount(ClassCategory category, int price) {
    int discountPercent = 0;
    
    if (category == ClassCategory.ELECTRONICS) {
    	discountPercent = 10;
    } else if (category == StringCategory.CLOTHING) {
    	discountPercent = 20;
    } else if (category == StringCategory.BOOKS) {
    	discountPercent = 15;
    } else {
    	System.out.println("category + "는 할인되지 않습니다.");
    }
    
    return price * discountPercent / 100;
}
public class ClassCategoryMain {
	public static void main(String[] args) {
    	int price = 100_000;
        
        DiscountService discountService = new DiscountService();
        int electronics = discountService.discount(ClassCategory.ELECTRONICS, price);
        System.out.println("Electronics의 할인된 금액: " + electronics); //10000
    }
}

열거형(Enum Type)

직접 열거형 패턴을 사용하여 클래스를 만들 수 있지만, 열거형을 사용할 때마다 매번 직접 구현하려면 많은 코드를 작성해야 한다. 그래서 자바는 타입에 안전한 열거형 패턴을 편리하게 사용할 수 있는 열거형(Enum Type)을 제공한다.

특징

  • 열거형은 클래스
  • 자동으로 java.lang.Enum을 상속 받음
  • 외부에서 임의로 생성할 수 없음
  • 인터페이스 구현 가능

장점

  • 타입 안전성 제공
  • 간결성 및 일관성: 코드의 가독성 높임
  • 확장성: 새로운 값을 추가하고 싶을 때, ENUM에 새로운 상수를 추가하면 됨
  • 예상 가능한 값들의 집합 표현

주요 기능

메서드설명
values()모든 ENUM 상수를 포함하는 배열 반환
valueOf(String name)
valueOf(Class<T> enumType, String name)
주어진 이름과 일치하는 ENUM 상수 반환
지정된 enumType에서 주어진 name과 일치하는 ENUM 상수 반환
name()ENUM 상수의 이름을 문자열로 반환
ordinal()ENUM 상수의 선언 순서를 반환(0부터 시작)
toString()ENUM 상수의 이름을 문자열로 반환
name()과 유사하지만, toString()은 직접 오버라이드 가능
Class<E> getDeclaringClass()ENUM의 Class 객체 반환

예시

위의 코드를 열거형을 사용한 코드로 바꿔보자.

public enum Category {
	/**
    * 1. 상수이름
    * 2. 상수이름(값1, 값2, ...)
    **/
	ELECTRONICS(10), CLOTHING(20), BOOKS(15);
    
    private final int discountPercent;
    
    Category(int discountPercent) {
    	this.discountPercent = discountPercent;
    }
    
    public int getDiscountPercent() {
    	return discountPercent;
    }
    
    public int discount(int price) {
    	return price * discountPercent / 100;
    }
}
public class CategoryMain {
	public static void main(String[] args) {
    	int price = 100_000;
        
        printDiscount(Category.ELECTRONICS, price);
        printDiscount(Category.CLOTHING, price);
        printDiscount(Category.BOOKS, price);
    }
    
    private static void printDiscount(Category category, int price) {
    	System.out.println(category.name() + " 카테고리의 할인 금액: " +category.discount(price));
    }
}

  • 추상 메서드 사용 방법
public enum Category {
    ELECTRONICS(10) { int discount(int price) { return price * discountPercent / 100;}},
    CLOTHING(20) { int discount(int price) { return price * discountPercent / 100;}},
    BOOKS(15) { int discount(int price) { return price * discountPercent / 100;}};

    protected final int discountPercent;

    Category2(int discountPercent) {
        this.discountPercent = discountPercent;
    }

    public int getDiscountPercent() {
        return discountPercent;
    }

    abstract int discount(int price);
}

참고
Class Random
Java의 정석
김영한의 실전 자바 - 중급 1편

profile
공부 기록

0개의 댓글

관련 채용 정보