# Enum 이란?
- 열거형이라고도 하며, 특정 값들의 집합을 의미한다.
- 자바에서 특정 값(상수) 들의 집합을 표현하는데 사용된다.
- 예를 들어 계절을 표현할 때, `봄`, `여름`, `가을`, `겨울`을 표현할 때 사용할 수 있다.
## 과거엔 상수를 어떻게 정의했는가?
- 자바에서는 상수를 정의하는 몇가지 방법이 있다
- `static final` 키워드를 사용하여 정의
- `interface`를 사용하여 정의
- 자체 클래스를 사용하여 정의
- `enum`을 사용하여 정의
- `enum`은 자바 5부터 지원하는 기능이다. (이전 버전에서는 사용할 수 없다.)
### static final 키워드를 사용하여 정의
- `static final` 은 `상수`를 표현하기에 적합하기에 예전부터 많이 사용되었다.
```java
public class Season {
public static final int SPRING = 0;
public static final int SUMMER = 1;
public static final int FALL = 2;
public static final int WINTER = 3;
public static void main(String[] args) {
int season = Season.SPRING;
switch (season) {
case Season.SPRING:
System.out.println("봄");
break;
case Season.SUMMER:
System.out.println("여름");
break;
case Season.FALL:
System.out.println("가을");
break;
case Season.WINTER:
System.out.println("겨울");
break;
}
}
}
```
하지만 이 방법은 접근제어자들 때문에 가독성이 그렇게 좋지 못하다라는 단점이 존재하며, 그룹화가 되어있지 않다는 단점이 존재한다.
### interface를 사용하여 정의
- 인터페이스의 모든 멤버는 `public static final`이기 때문에 상수를 정의하기에 적합하다.
```java
public interface Season {
int SPRING = 0;
int SUMMER = 1;
int FALL = 2;
int WINTER = 3;
}
public class Main {
public static void main(String[] args) {
int season = Season.SPRING;
switch (season) {
case Season.SPRING:
System.out.println("봄");
break;
case Season.SUMMER:
System.out.println("여름");
break;
case Season.FALL:
System.out.println("가을");
break;
case Season.WINTER:
System.out.println("겨울");
break;
}
}
}
```
이 방법으로 정의 시 결국 상수가 `정수`로 정의되는 문제가 발생한다. 상수는 `변하지 않는 값`이기도 하지만 `고유한 값`이라는 이름도 내포되어 있다.
따라서 정수와 비교가 가능해지고, 정수와 비교 시 `참`이 나올 수도 있는 문제가 발생한다.
예를 들어 `Season.SPRING`과 `0`을 비교하면 `true`가 나올 수도 있다.
### 자체 클래스를 사용하여 정의
- 자체 클래스를 사용하여 정의하는 방법은 `static final` 키워드를 사용하여 정의하는 방법과 비슷하다.
- 부가적으로 생성자를 `private`으로 선언하여 외부에서 객체를 생성하지 못하도록 막아준다.
- 이 방법은 `static final` 키워드를 사용하여 정의하는 방법과 비슷하지만, `private` 생성자를 선언하여 외부에서 객체를 생성하지 못하도록 막아준다는 점이 다르다.
```java
public class Season {
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season FALL = new Season();
public static final Season WINTER = new Season();
private Season() {
}
}
```
```java
public class Main {
public static void main(String[] args) {
Season season = Season.SPRING;
if (season == Season.SPRING) {
System.out.println("봄");
} else if (season == Season.SUMMER) {
System.out.println("여름");
} else if (season == Season.FALL) {
System.out.println("가을");
} else if (season == Season.WINTER) {
System.out.println("겨울");
}
}
}
```
이 방법을 사용할 경우 `정수`가 아닌 `객체`로 정의되기 때문에 정수와 비교할 수 없다는 장점이 있지만 가독성이 좋지 않다는 단점과 `switch`를 사용할 수 없다는 단점이 존재한다.
`switch` 조건에 들어가는 데이터 타입은 `정수`, `문자열`, `Enum`만 가능하기 때문이다.
## 자바의 Enum
- 자바에서는 `Enum`을 사용하여 상수를 정의할 수 있다.
- C언어의 `enum`은 단순한 정수형 상수를 정의한다
- 자바의 Enum은 `java.lang.Enum` 클래스를 상속받는 특수한 **특수한 클래스**다
- 클래스이기 때문에 생성자, 필드, 메서드를 가질 수 있다.
- Enum은 열거형 상수들을 관리하는 클래스이다.
- 열거형 상수들은 Enum 클래스의 `static final` 멤버들이다.
- 생성자의 접근 제어자는 `private`이다.
- 외부에서 객체를 생성할 수 없다.
- Enum 클래스의 생성자는 다음과 같은 특징을 가진다.
- `private`이다.
- JVM에 의해 호출된다.
- Enum 클래스의 멤버들을 초기화하는 역할을 한다.
- Enum 클래스의 멤버들은 다음과 같은 특징을 가진다.
- `public static final`이다.
- 생성자에 의해 초기화된다.
- 멤버들은 Enum 클래스의 객체이다.
- `==` 연산자를 통해 비교할 수 있다.
- 단 한 번만 생성되기는게 보장되기 때문에 참조 비교를 해도 된다.
## Enum의 장점
- 코드가 단순해지며 가독성이 좋아진다
- 키워드가 `enum`이기 때문에 상수임을 알 수 있다
- 허용 가능한 값들을 제한할 수 있다
- Type Safety를 보장한다
- switch 문을 사용할 수 있다
- 여러 IDE의 도움을 받을 수 있다
- 자동완성, 오타 검증, 리팩토링 등
- 본질적으로 Thread Safe 하다
- Serialization이 자동으로 처리된다
## Enum 정의하기
```java
enum 열거형이름 {
열거형 상수1,
열거형 상수2,
열거형 상수3,
...
}
```
### Enum 정의 예시
```java
public enum Season {
SPRING,
SUMMER,
FALL,
WINTER
}
```
> 위 예제에서 `Season`은 Enum의 이름이고, `SPRING`, `SUMMER`, `FALL`, `WINTER`는 Season Enum의 멤버들이다.
## Enum의 고급 기능
- Enum은 클래스이기 때문에 생성자, 필드, 메서드를 가질 수 있다.
```java
public enum Season {
SPRING("봄"),
SUMMER("여름"),
FALL("가을"),
WINTER("겨울");
private final String name;
Season(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
```
## Enum의 메서드
- 모든 클래스가 `Object` 클래스를 자동 상속하는 것 처럼, Enum 클래스도 무조건 `java.lang.Enum` 이라는 클래스의 상속을 받는다.
- `java.lang.Enum` 클래스에는 자체 내장 메서드를 가지고 있으며, 이를 사용할 수 있다.
| 메서드 이름 | 설명 |
| ----------- | ------------------------------------------------------------ |
| values() | Enum의 모든 멤버들을 배열로 반환한다 |
| valueOf() | Enum의 멤버 이름으로 Enum 멤버를 찾아서 반환한다 |
| ordinal() | Enum의 멤버가 정의된 순서를 반환한다 |
| compareTo() | Enum의 멤버가 정의된 순서를 기준으로 비교하여 순서가 앞인지 뒤인지를 반환한다 |
| name() | Enum의 멤버 이름을 반환한다 |
### values()
- Enum의 모든 멤버들을 배열로 반환한다
```java
public enum Season {
SPRING,
SUMMER,
FALL,
WINTER
}
public class Main {
public static void main(String[] args) {
Season[] seasons = Season.values();
System.out.println(Arrays.toString(season));
}
}
```
### valueOf()
- Enum의 멤버 이름으로 Enum 멤버를 찾아서 반환한다
```java
public enum Season {
SPRING,
SUMMER,
FALL,
WINTER
}
public class Main {
public static void main(String[] args) {
Season season = Season.valueOf("SPRING");
System.out.println(season);
}
}
```
### ordinal()
- Enum의 멤버가 정의된 순서를 반환한다
```java
public enum Season {
SPRING,
SUMMER,
FALL,
WINTER
}
public class Main {
public static void main(String[] args) {
Season season = Season.SPRING;
System.out.println(season.ordinal());
}
}
```
### compareTo()
- Enum의 멤버가 정의된 순서를 기준으로 비교하여 순서가 앞인지 뒤인지를 반환한다
```java
public enum Season {
SPRING,
SUMMER,
FALL,
WINTER
}
public class Main {
public static void main(String[] args) {
Season season1 = Season.SPRING;
Season season2 = Season.SUMMER;
System.out.println(season1.compareTo(season2));
}
}
```
### name()
- Enum의 멤버 이름을 반환한다
```java
public enum Season {
SPRING,
SUMMER,
FALL,
WINTER
}
public class Main {
public static void main(String[] args) {
Season season = Season.SPRING;
System.out.println(season.name());
}
}
```