이번 주 멘토링 과제는 enum [whiteship:live-study] 11주차 과제: Enum 이다.
자바를 오랜만에 공부하다보니 관련 개념을 아예 잊어버리고 있었는데, 내부 코드를 찾아보면서 하나씩 찾아보았다.
Java enum 은 제한된 값, 상수 값들의 목록의 가지는 타입을 의미한다. (enum 은 ‘Enumeration’ 의 약자로 열거, 목록이라는 뜻)
예전에는 특정 상수값을 사용하기 위해서 모두 상수로 선언했어야 한다. enum은 관련있는 상수 값들을 묶어 사용할 수 있도록 해준다. 대표적인 예로 요일, 계절, 제품 카테고리 등을 enum을 통해 사용할 수 있다.
enum 키워드를 통해 아래와 같이 정의한다. (열거 상수는 대문자로 작성한다.)
단순하게 정의하는 경우
public enum Season {
SPRING,
SUMMER,
FALL,
WINTER
}
enum 에서 제공해주는 name() 메소드를 사용할 수도 있다. name() 은 호출된 값의 이름을 String으로 리턴한다.
Season season1 = Season.FALL;
System.out.println(season1); // 출력: FALL
System.out.println(season1.name()); // 출력: FALL
각각의 요소들에 특정 값을 넣는 경우
아래와 같이 생성자와 필드값을 추가할 수 있다. 단, new 키워드를 통해 인스턴스 생성은 불가하다.
public enum Season {
SPRING("봄", 0),
SUMMER("여름", 1),
FALL("가을", 2),
WINTER("겨울", 3)
;
private final String label;
private final String number;
Season(String label, int number) {
this.label = label;
this.number = number;
}
public String label() { return label; }
public int number() { return number; }
}
Season season1 = Season.FALL;
System.out.println(season1.name()); // 출력: FALL
System.out.println(season1.label()); // 출력: 가을
System.out.println(season1.number()); // 출력: 2
클래스 안에 정의되는 경우
public class User {
private Tier tier;
public enum Tier {
BRONZE,
SILVER,
GOLD
}
}
enum 의 요소들을 순서대로 enum 타입의 배열로 리턴한다.
Season.values();
매개변수로 주어진 String과 열거형 상수에서 일치하는 이름을 가진 원소를 반환한다. 일치하는 원소가 없는경우 IlleagalArgumentException 예외가 발생한다.
Season summer = Season.valueOf("SUMMER");
enum은 class 키워드가 아닌 enum 키워드로 만들지만, enum 또한 클래스이고 object 클래스를 상속 받는다.
eunm 키워드를 통해 만들어진 모든 enum 타입은 모두java.lang.Enum클래스를 상속 받는다.
toString() 이나 name() 을 통해서 접근할 수 있다. 
ordnal() 을 통해 접근할 수 있다. ordinal 값은 선언된 순서에 따라 변경되므로 해당 값은 사용하는 것은 좋지 않다. 보통 개발자들이 직접 사용하지는 않고, EnumSet이나 EnumMap과 같은 Enum기반 데이터 구조에서 사용한다. 

== 을 통해 비교하는데, enum 상수는 인스턴스가 단 하나만 생성되기 때문이다. (싱글톤)


compareTo() : 열거형 상수의 순서를 비교한다. 순서가 낮은 경우 음수, 같은 경우 0, 큰 경우 양수 반환.
💡모든 열거형 상수를 가져오는
values()은 java.lang.Enum 에 정의되어 있지 않고, 컴파일러가 enum을 만들 때 추가해주는 메소드이다.
원소들이 enum 상수로만 이루어진 경우, enum을 위한 자료구조를 사용할 수 있는데 그 중 EnumSet이 있다. EnumSet은 Set 인터페이스를 구현하면서 AbstractSet을 상속하지만 대부분의 메서드를 재정의해서 사용한다.
ConcurrentModificationException 이 발생하지 않는다.빈 열거형 셋을 만들 때, 아래 메서드가 호출된다.
생성할 때, 열거형 상수의 갯수에 따라 RegularEnumSet 과 JumboEnumSet으로 나뉘어 생성된다.
RegularEnumSet 은 long의 bit(64bit)를 기준으로 각 비트가 현재 열거형에서의 상수 위치를 반영하기 때문에 해당 값이 존재하는지 파악하는 것이 매우 빠르기 때문이다.

이렇게 구현되어 EnumSet의 모든 메서드는 산술 비트 연산을 사용해서 구현되어 있다.

보통 HashSet보다 빠르며 대량 작업도 일정한 시간에 수행된다. Set 값을 변경하는 게 아니라 조회를 할 경우 EnumSet을 사용하며 최적화할 수 있다.
인스턴스를 생성하는 메서드를 제외하고, 대부분 Set 과 동일하게 동작한다.
public enum Tier {
IRON,
BRONZE,
SILVER,
GOLD
}
// 모든 요소를 포함하는 EnumSet 생성한다.
EnumSet allTier = EnumSet.allOf(Tier.class);
//매개변수로 받는 열거형을 비운 EnumSet을 반환한다.
EnumSet.allOf(Tier.class);
// 매개변수로 받는 해당 요소를 찾아서 넣는다.
EnumSet.of(Tier.BRONZE, Tier.SILVER);
// 매개변수로 받는 요소들만 빼고 넣는다.
EnumSet.complementOf(Tier.BRONZE)
// 두 구간안에 해당하는 요소를 넣는다.
EnumSet.range(Tier.IRON, Tier.SILVER)
// add(), remove(), contains() 등 사용