▸JAVA/기본 문법

열거형 클래스 (Enum Class)

코데방 2019. 12. 10.
728x90

[ 열거형 클래스(enum class) ]

  • 상수(final) 전용 클래스
  • 코드는 짧고 의미를 강하게 하는 효과가 있음
  • 정해진 상수를 매개변수로 받아야 하는 메소드의 매개변수를 강제할 수 있음

조금 어려운 개념인데 위의 세 가지 항목을 예시와 함께 정리해보겠습니다. 상세한 클래스 메소드 사용법은 아래 링크를 참조하시면 됩니다.

 

2019/12/10 - [JAVA/라이브러리(API)] - java.lang.Enum (열거형) 주요 메소드 [1/1]

 


 

상수(미리 정해진 값)을 사용하는 경우, 먼저 final 필드를 사용하는 방법이 있습니다. 예를 들어 제품 종류에 따른 크기와 색깔이 정해진 상수를 모아둔 클래스가 있고, 이를 필요로 하는 다른 클래스에서 가져다가 출력해주는 메소드가 있다고 가정해보겠습니다. 아래와 같은 코드로 작성이 가능합니다.

 

package study.first;

public class Main {

	public static void main(String[] args) {

		printProduct(FinalValues.CLOCK_SIZE, FinalValues.CLOCK_COLOR);		
		
	}	
	
	// 제품의 사이즈와 색깔 출력 메소드
	static void printProduct(int size, String color) {		

		System.out.println(size);
		System.out.println(color);			
	}
}

/* 상수 정의 */
class FinalValues {

	// 시계
	static final int CLOCK_SIZE = 100;
	static final String CLOCK_COLOR = "White";

	// 책
	final static int BOOK_SIZE = 200;
	final static String BOOK_COLOR = "Blue";
}

 

 

하지만 조금 불편한 점이 있습니다. 일단 메소드 측에서 "시계 사이즈 : 100, 시계 색깔 : White"과 같이 인자값에 따라 그 종류를 알아채고 출력할 방법이 없습니다. 조금 더 복잡하게 코드를 짜면 구현은 할 수 있겠지만 꽤나 번거롭고 상수가 추가될 때 수정해줘야할 코드가 늘어납니다.

그리고 만약 메소드를 가져와서 사용하는 사람이 실수로 인자값을 잘 못 넣을 수도 있습니다. 정해진 상수를 넣어줘야 하는데 아래와 같이 그냥 본인 마음대로 숫자를 집어넣을 수도 있습니다. 이 경우 바로 문제가 되지 않더라도 나중에 상수 값을 변경할 경우 같이 바뀌지 않는다는 문제점이 생깁니다. 실무에서는 실제로 프로젝트 외주 인력이 귀찮다고 이런 식으로 하드코딩을 해둔게 나중에 장애로 이어지는 경우가 종종 발생합니다.

public class Main {

	public static void main(String[] args) {

		printProduct(100, "White");	 // 개발자가 하드코딩할 위험성 존재
	}	

 


 

이런 문제들을 간단히 해결해 줄 수 있는 기능이 열거형 클래스(Enum Class)입니다. 똑같은 케이스를 Enum Class를 이용해보겠습니다.

먼저 작성법은 아래와 같습니다. 첫 줄에 열거 상수를 나열해 주고, 만약 대입되는 값을 넣고 싶다면 괄호 안에 넣어주면 됩니다. 앞이 변수 이름이고 괄호 안이 값입니다. 그리고 무조건 값(괄호 안)을 담을 필드를 생성하고 생성자 선언을 해줘야 합니다. Enum Class 타입의 인스턴스가 만들어질 때 생성자(변수 이름)에 따라 값이 해당 필드에 들어가게 되고, 그 값을 이용하게 됩니다.

enum FinalValues {

	// enum 클래스의 열거 상수 (자동으로 public static final로 선언)
	CLOCK_SIZE(100), CLOCK_COLOR("White"), BOOK_SIZE(200), BOOK_COLOR("Blue");

	// 값을 담을 필드 생성(private 캡슐화)
	private int size;
	private String color;

	// size 생성자 선언
	FinalValues(int size) {
		this.size = size;
	}

	// color  생성자 선언
	FinalValues(String color) {
		this.color = color;
	}
	
	// size getter
	int getSize() {
		return size;
	}
	
	// color getter
	String getColor() {
		return color;
	}		
}

 

 

이제 Enum Class에 정의된 내용을 사용해서 시계의 크기와 색깔을 출력해 보겠습니다. 생성자 선언 문법이 일반 클래스와 다릅니다. 일반적으로 new class(생성자) 형태였다면 Enum Class에서는 class.생성자 형태고, 생성자가 가진 값을 찾아서 필드에 넣어준 뒤 생성된 인스턴스를 반환해줍니다.

 

먼저 아래와 같이 생성된 인스턴스를 따로 저장하지 않고 각 타입의 값만 받아오도록 해보겠습니다. final static 변수와 같이 Enum 클래스에서 정의된 값을 받아와 변수에 넣어 사용할 수 있습니다.

 

public class Study {

	public static void main(String[] args) {

	int clockSize = FinalValues.CLOCK_SIZE.getSize();
	String clockColor = FinalValues.CLOCK_COLOR.getColor();
	
	printProduct(clockSize, clockColor);
	}

	// 제품의 사이즈와 색깔 출력 메소드
	static void printProduct(int size, String color) {

		System.out.println(size);
		System.out.println(color);
	}
}

 


 

Enum Class를 위와 같은 방식으로 사용이 가능하지만, 아까의 문제점을 해결하지는 못했습니다. 여전히 하드코딩이 가능한 형태입니다. Enum Class를 제대로 이용하기 위해서는 아래와 같이 사용할 수 있습니다.

먼저 Enum Class 타입의 인스턴스를 하나 만들어 줍니다. 이 때 생성자를 위의 경우와 같이 "class.생성자" 형태로 넣어주면 됩니다. 그리고 메소드에서도 매개변수를 Enum Class 타입으로 받아줍니다. 이렇게 되면 이 메소드에는 위와 같이 사용자가 바로 숫자와 문자열을 넣어서 완성시킬 수가 없고 무조건 Enum Class를 사용해야 해서 하드 코딩의 실수를 막을 수 있습니다.

또한 java.lang.Enum 클래스에서 오버라이딩된 toString() 메소드를 이용해 해당 값 뿐만 아니라 값의 이름도 알아낼 수 있습니다. 뿐만 아니라 다른 메소드들도 제공하는데 다음 글에서 정리해 보겠습니다.

 

package study.first;

public class Study {

	public static void main(String[] args) {


		FinalValues size = FinalValues.CLOCK_SIZE;
		FinalValues color = FinalValues.CLOCK_COLOR;
		
		printProduct(size, color);
	
	}

	// 제품의 사이즈와 색깔 출력 메소드
	static void printProduct(FinalValues size, FinalValues color) {

		// 사이즈와 컬러 값 출력
		System.out.println(size + " : " + size.getSize());
		System.out.println(color + " : " + color.getColor());
		
	}
}

enum FinalValues {

	// enum 클래스의 열거 상수 (자동으로 public static final로 선언)
	CLOCK_SIZE(100), CLOCK_COLOR("White"), BOOK_SIZE(200), BOOK_COLOR("Blue");

	// 값을 담을 필드 생성(private 캡슐화)
	private int size;
	private String color;

	// size 생성자 선언
	FinalValues(int size) {
		this.size = size;
	}

	// color  생성자 선언
	FinalValues(String color) {
		this.color = color;
	}
	
	// size getter
	int getSize() {
		return size;
	}
	
	// color getter
	String getColor() {
		return color;
	}		
}

 


 

또 한가지 Enum Class의 장점은 컴파일 시점에 따른 오류를 방지할 수 있다는 것입니다. 만약 다른 클래스에서 정의한 final 상수를 "int a = valueClass.value(상수)" 형태로 사용한 클래스가 있다면, 이 클래스를 컴파일 할 때 상수값을 바로 코드에 넣어버립니다. 즉 컴파일 시점에 valueClass.value가 1이었다면 "a = 1"로 컴파일 됩니다. 만약 컴파일 이후에 누군가 상수의 값을 바꿨더라도 a 변수가 있는 클래스를 다시 컴파일해주지 않는 한 코드에는 "a = 1"로 그대로 있습니다. 대입되는 값이 변수가 아닌 상수가 되는 것이죠.

Enum Class를 사용해서 변수에 값을 넣어줄 경우 컴파일 될 때 상수가 아닌 변수로 인식합니다. "a = value" 형태로 컴파일 되기 때문에 런타임 시 동적으로 값을 찾아옵니다. 누군가 상수를 바꿨더라도 바로 적용되기 때문에 컴파일 시점에 따른 오류를 방지할 수 있게 됩니다.

728x90

댓글

💲 추천 글