Enum을 사용하는 이유
자바 enum은 서로 연관된 상수를 편하게 선언하여 활용할 수 있게 해준다. 보통 서로 연관된 상수들의 집합이라 정의한다. 자바는 final로 String과 같은 문자열이나 숫자들을 나타내는 기본 자료형 값을 고정할 수 있다. 상수란 변하지 않는 고정 값을 의미한다. 어떤 상수 값들을 사용하고 있고, 그러한 상수들이 서로 연관될 때 상수들을 그룹화하여 관리할 수 있다.
예시
기본적인 예시로 요일을 사용할 수 있다. 요일에 대한 값은 상수고 변하지 않는다.
public class Exaample {
public static void main(String[] args) {
int day = 1;
switch (day) {
case 1:
System.out.println("월요일");
break;
case 2:
System.out.println("화요일");
break;
case 3:
System.out.println("수요일");
break;
case 4:
System.out.println("목요일");
break;
case 5:
System.out.println("금요일");
break;
}
}
}
위와 같은 코드가 있을 때 switch 조건 case를 매직넘버라고 불리며 매직넘버를 final 변수로 선언하여 사용한다.
매직넘버란 : 의미 있는 이름의 상수로 대체될 수 있는 숫자. 의미있는 문자열은 매직 리터럴이다.
public class Exaample {
private final static int MONDAY = 1;
private final static int TUESDAY = 2;
private final static int WEDNESDAY = 3;
private final static int THURSDAY = 4;
private final static int FRIDAY = 5;
public static void main(String[] args) {
int day = FRIDAY;
switch (day) {
case MONDAY:
System.out.println("월요일");
break;
case TUESDAY:
System.out.println("화요일");
break;
case WEDNESDAY:
System.out.println("수요일");
break;
case THURSDAY:
System.out.println("목요일");
break;
case FRIDAY:
System.out.println("금요일");
break;
}
}
}
이렇게 하면 코드 가독성이 좋아진다. 그래서 매직넘버를 없앤다. 하지만, 생각을 좀 하면 상수들의 연관성을 알 수 있다. Enum으로 관리해보자.
enum Day {
MONDAY("월요일"),
TUESDAY("화요일"),
WEDNESDAY("수요일"),
THURSDAY("목요일"),
FRIDAY("금요일");
String kor;
Day(String kor) {
this.kor = kor;
}
public String getKor() {
return kor;
}
}
public class EnumTest {
public static void main(String[] args) {
Day day = Day.FRIDAY;
switch (day) {
case MONDAY:
System.out.println(Day.MONDAY.getKor());
break;
case TUESDAY:
System.out.println(Day.TUESDAY.getKor());
break;
case WEDNESDAY:
System.out.println(Day.WEDNESDAY.getKor());
break;
case THURSDAY:
System.out.println(Day.THURSDAY.getKor());
break;
case FRIDAY:
System.out.println(Day.FRIDAY.getKor());
break;
}
}
}
enum을 사용하면 문자열과 같이 상수를 정의하여 관리하고 사용할 수 있다.
enum의 장점과 특징
- 가독성 : enum을 사용하면 의미있는 이름을 부여하게 되면서 코드를 읽기 수월해진다.
- 이름 중복 : 위에 코드예시에서는 나와있지 않지만 같은 이름에도 다른 의미를 부여할 수 있다. 예) Fruit.APPLE, Company.APPLE
- 클래스화 : enum은 클래스처럼 변수를 선언하고 행위를 정의할 수 있다. 하지만 enum은 상수이기 때문에 생성자를 public으로 선언할 수 없다. 런타임 시점에 동적으로 값을 할당할 수 없다. 또한, 내부적으로 java.lang.enum을 상속받기 때문에 상속을 방지할 수 있다. 이러한 특징은 타입 안정성을 보장한다.
- 추상메서드 : enum은 선언한 값들마다 다른 행위를 가지는 추상메서드를 부여하고 사용할 수 있다.
- 싱글톤 : enum은 싱글톤이다. enum안에 변수를 선언하고 값을 변경한다면? enum은 static이다. 값을 공유하기 때문에 사용하게 된다면 주의해야한다. (멀티 쓰레드)
enum의 기본 메소드
- name() : enum의 문자열을 리턴한다.
- ordinal() : index 값을 리턴한다.
- caompareTo() : enum값을 비교해서 index 차이를 리턴한다.
- valueOf(String name) : 문자열의 맞는 enum값을 리턴한다.
- values : enum 값들을 배열로 반환한다.
enum 메서드 정의하기
얼마전에 아시안 게임이 있었다. 진짜 재밌게 봤다. 수영은 언제 봐도 재밌고, 축구도 야구도 재밌었다. 어쨌든 아시안 게임에서 매달별 상금이 있다고 하자.
public enum MedalAmount {
GOLD(10_000_000), SILVER(5_000_000), BRONZE(500_000);
int amount;
MedalAmount(int amount) {
this.amount = amount;
}
}
한 사람의 상금 총 합계를 구하고 싶다. enum에서 정의하고 구현할 수 있지 않을까?
public enum MedalType {
GOLD(10_000_000), SILVER(5_000_000), BRONZE(500_000);
int amount;
MedalType(int amount) {
this.amount = amount;
}
public static Long sumAmountByPerson(Person person) {
Map<MedType, Integer> receviedMedals = person.getMedalToMap();
long totAmount = 0;
receviedMedals.forEach((medalType, count) -> {
totAmount += medalType.amount * count;
});
return totAmount;
}
}
sumAmountByPerson으로 메서드명을 정의하고 person을 매게변수로 받는다. pserson은 자신이 획득한 메달을 Map형식으로 반환할 수 있다. 반환 된 Map에는 메달별 획득한 개수가 들어있다. 그리고 총 상금 금액을 반환한다.
이렇게 enum에 static 메서드로 기능을 추가하는 방식이 적합한 지는 모르겠다. enum을 제대로 사용해봤던 경험이 많이 없다. 아직 공부하는 입장이라 많은 사례들을 접해보고 경험한 다음에 다시 enum 관련된 포스팅을 해볼 것 이다.
참고
- https://okky.kr/articles/384729 - 댓글참고
- https://jojoldu.tistory.com/137 - 내용참고
- https://inor.tistory.com/12