선장님과 함께하는 자바 스터디입니다.
자바 스터디 Github
github.com/whiteship/live-study
나의 Github
github.com/cmg1411/whiteShip_live_study
- enum 정의하는 방법
- enum이 제공하는 메소드 (values()와 valueOf())
- java.lang.Enum
- EnumSet
enum
- 열거형이라고도 부른다.
- 한정된 타입만 갖고 상수만 모아놓은 데이터 타입.
- Type-Safe 한 문제를 해결하기 위해 나왔다.
enum 의 정의 방법
기본적으로 enum은 클래스와 같다. 클래스를 선언할 때 붙이는 class 대신 enum 을 붙이면 된다.
접근 지정자 역시 클래스와 같이 public, package-private 만 허용된다.
public enum Week {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
enum 은 특수한 형태의 클래스이므로 인스턴스 변수, 생성자, 메서드를 쓸 수 있다.
public enum Week {
MONDAY("월요일"),
TUESDAY("화요일"),
WEDNESDAY("수요일"),
THURSDAY("목요일"),
FRIDAY("금요일"),
SATURDAY("토요일"),
SUNDAY("일요일");
private String korean;
EnumEx(String korean) {
this.korean = korean;
}
public String getWeekKorean() {
return korean;
}
}
인스턴스 변수를 선언하고 생성자로 인스턴스 변수값을 초기화해준다.
그리고 그 값을 enum 상수 이후에 () 안에 나열한다.
MONDAY("월요일") 로 생성자를 호출한다는 것을 잘 보면 이런 의문이 생긴다.
그럼 MONDAY는 객체인가 ?
정답은 맞다. 이에 대해서는 조금 있다가 자세히 알아보자.
enum의 사용은 아래와 같다.
public static void main(String[] args) {
Week today = Week.FRIDAY;
}
enum 이전의 Type-safe 문제
- 상수를 정의하는 방법은 final static 이라고 잘 알려져 있다.
- enum 이 없을 때에는 상수를 사용하는 클래스나 인터페이스에서 상수를 정의하여 사용하였다.
- 하지만 이 상수들은 type-safe 하지 못하다.
- 아래 예를 보자.
타입에 불안정적이다 : 컴파일 타임에 타입을 구분 하지 못해 Runtime 시 타입으로 인한 문제가 발생하는 것.
Type Safe 하다 : 타입을 판별 할 수 있어 타입이 다르면 Runtime시가 아닌 컴파일시 문제를 잡을 수 있는 것.
문제는 항상 컴파일 타임에 발견하는 것이 좋다.
public class notTypeSafe {
public static void main(String[] args) {
if (FruitConst.MELON == MusicApp.MELON) {
System.out.println("이게 왜 같아 !");
}
}
}
class FruitConst {
public static final int APPLE = 1;
public static final int MELON = 2;
public static final int PITCH = 3;
}
class MusicApp {
public static final int BUGS = 1;
public static final int MELON = 2;
public static final int APPLEMUSIC = 3;
}
FruitConst.MELON 과 MusicApp.MELON 은 둘 다 값이 1이다.
하지만 음악 앱의 멜론과 과일 멜론은 분명히 다르다.
또, 다른 클래스에서 선언했다. 이 둘은 분명히 다른 개체이다.
하지만 == 를 이용한 동일성 검사에서는 같다고 나온다.
이것이 type-safe 하지 못한 상수이다. 이 둘이 같다고 처리한다면 분명히 런타임시에 오류가 발생할 코드가 있을 것이다.
오타로 인해 오류가 발생할 수 있는 상황도 타입 세이프티하지 않다고 한다.
일례로, JPA 의 queryDSL 도 타입 세이프티를 위한 방법이라 할 수 있다.
Type-safe 한 enum
public class TypeSafeEnum {
public static void main(String[] args) {
FruitConst2 fruit_melon = FruitConst2.MELON;
MusicApp2 music_melon = MusicApp2.MELON;
if (fruit_melon == music_melon) {
System.out.println("이게 왜 같아!");
}
}
}
enum FruitConst2 {
APPLE,
MELON,
PITCH;
}
enum MusicApp2 {
BUGS,
MELON,
APPLEMUSIC;
}
이 코드는 애초에 if 문의 조건에서 컴파일 에러가 뜬다.
다른 타입끼리는 비교할 수 없다는 것이다.
이것이 Type-safe 하다는 의미이다.
java.lang.Enum
- java.lang 패키지에는 Enum 이라는 클래스가 있다.
- 우리가 배운 enum 은 클래스의 일종인데 이 클래스는 뭐지? 라는 생각이 들 수 있다.
- 먼저 enum을 정의하고 바이트코드를 뽑아보자. (위의 일주일 enum 바이트코드이다)
// class version 52.0 (52)
// access flags 0x4031
// signature Ljava/lang/Enum<Lcom/whiteship/white_ship_study/week11/Week;>;
// declaration: com/whiteship/white_ship_study/week11/Week extends java.lang.Enum<com.whiteship.white_ship_study.week11.Week>
public final enum com/whiteship/white_ship_study/week11/Week extends java/lang/Enum {
// compiled from: Week.java
// access flags 0x4019
public final static enum Lcom/whiteship/white_ship_study/week11/Week; MONDAY
// access flags 0x4019
public final static enum Lcom/whiteship/white_ship_study/week11/Week; TUESDAY
// access flags 0x4019
public final static enum Lcom/whiteship/white_ship_study/week11/Week; WEDNESDAY
// access flags 0x4019
public final static enum Lcom/whiteship/white_ship_study/week11/Week; THURSDAY
// access flags 0x4019
public final static enum Lcom/whiteship/white_ship_study/week11/Week; FRIDAY
// access flags 0x4019
public final static enum Lcom/whiteship/white_ship_study/week11/Week; SATURDAY
// access flags 0x4019
public final static enum Lcom/whiteship/white_ship_study/week11/Week; SUNDAY
// access flags 0x2
private Ljava/lang/String; korean
// access flags 0x101A
private final static synthetic [Lcom/whiteship/white_ship_study/week11/Week; $VALUES
// access flags 0x9
public static values()[Lcom/whiteship/white_ship_study/week11/Week;
L0
LINENUMBER 3 L0
GETSTATIC com/whiteship/white_ship_study/week11/Week.$VALUES : [Lcom/whiteship/white_ship_study/week11/Week;
INVOKEVIRTUAL [Lcom/whiteship/white_ship_study/week11/Week;.clone ()Ljava/lang/Object;
CHECKCAST [Lcom/whiteship/white_ship_study/week11/Week;
ARETURN
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x9
public static valueOf(Ljava/lang/String;)Lcom/whiteship/white_ship_study/week11/Week;
// parameter mandated name
L0
LINENUMBER 3 L0
LDC Lcom/whiteship/white_ship_study/week11/Week;.class
ALOAD 0
INVOKESTATIC java/lang/Enum.valueOf (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
CHECKCAST com/whiteship/white_ship_study/week11/Week
ARETURN
L1
LOCALVARIABLE name Ljava/lang/String; L0 L1 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x2
// signature (Ljava/lang/String;)V
// declaration: void <init>(java.lang.String)
private <init>(Ljava/lang/String;ILjava/lang/String;)V
// parameter synthetic $enum$name
// parameter synthetic $enum$ordinal
// parameter korean
L0
LINENUMBER 14 L0
ALOAD 0
ALOAD 1
ILOAD 2
INVOKESPECIAL java/lang/Enum.<init> (Ljava/lang/String;I)V
L1
LINENUMBER 15 L1
ALOAD 0
ALOAD 3
PUTFIELD com/whiteship/white_ship_study/week11/Week.korean : Ljava/lang/String;
L2
LINENUMBER 16 L2
RETURN
L3
LOCALVARIABLE this Lcom/whiteship/white_ship_study/week11/Week; L0 L3 0
LOCALVARIABLE korean Ljava/lang/String; L0 L3 3
MAXSTACK = 3
MAXLOCALS = 4
// access flags 0x1
public getWeekKorean()Ljava/lang/String;
L0
LINENUMBER 19 L0
ALOAD 0
GETFIELD com/whiteship/white_ship_study/week11/Week.korean : Ljava/lang/String;
ARETURN
L1
LOCALVARIABLE this Lcom/whiteship/white_ship_study/week11/Week; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 4 L0
NEW com/whiteship/white_ship_study/week11/Week
DUP
LDC "MONDAY"
ICONST_0
LDC "\uc6d4\uc694\uc77c"
INVOKESPECIAL com/whiteship/white_ship_study/week11/Week.<init> (Ljava/lang/String;ILjava/lang/String;)V
PUTSTATIC com/whiteship/white_ship_study/week11/Week.MONDAY : Lcom/whiteship/white_ship_study/week11/Week;
L1
LINENUMBER 5 L1
NEW com/whiteship/white_ship_study/week11/Week
DUP
LDC "TUESDAY"
ICONST_1
LDC "\ud654\uc694\uc77c"
INVOKESPECIAL com/whiteship/white_ship_study/week11/Week.<init> (Ljava/lang/String;ILjava/lang/String;)V
PUTSTATIC com/whiteship/white_ship_study/week11/Week.TUESDAY : Lcom/whiteship/white_ship_study/week11/Week;
L2
LINENUMBER 6 L2
NEW com/whiteship/white_ship_study/week11/Week
DUP
LDC "WEDNESDAY"
ICONST_2
LDC "\uc218\uc694\uc77c"
INVOKESPECIAL com/whiteship/white_ship_study/week11/Week.<init> (Ljava/lang/String;ILjava/lang/String;)V
PUTSTATIC com/whiteship/white_ship_study/week11/Week.WEDNESDAY : Lcom/whiteship/white_ship_study/week11/Week;
L3
LINENUMBER 7 L3
NEW com/whiteship/white_ship_study/week11/Week
DUP
LDC "THURSDAY"
ICONST_3
LDC "\ubaa9\uc694\uc77c"
INVOKESPECIAL com/whiteship/white_ship_study/week11/Week.<init> (Ljava/lang/String;ILjava/lang/String;)V
PUTSTATIC com/whiteship/white_ship_study/week11/Week.THURSDAY : Lcom/whiteship/white_ship_study/week11/Week;
L4
LINENUMBER 8 L4
NEW com/whiteship/white_ship_study/week11/Week
DUP
LDC "FRIDAY"
ICONST_4
LDC "\uae08\uc694\uc77c"
INVOKESPECIAL com/whiteship/white_ship_study/week11/Week.<init> (Ljava/lang/String;ILjava/lang/String;)V
PUTSTATIC com/whiteship/white_ship_study/week11/Week.FRIDAY : Lcom/whiteship/white_ship_study/week11/Week;
L5
LINENUMBER 9 L5
NEW com/whiteship/white_ship_study/week11/Week
DUP
LDC "SATURDAY"
ICONST_5
LDC "\ud1a0\uc694\uc77c"
INVOKESPECIAL com/whiteship/white_ship_study/week11/Week.<init> (Ljava/lang/String;ILjava/lang/String;)V
PUTSTATIC com/whiteship/white_ship_study/week11/Week.SATURDAY : Lcom/whiteship/white_ship_study/week11/Week;
L6
LINENUMBER 10 L6
NEW com/whiteship/white_ship_study/week11/Week
DUP
LDC "SUNDAY"
BIPUSH 6
LDC "\uc77c\uc694\uc77c"
INVOKESPECIAL com/whiteship/white_ship_study/week11/Week.<init> (Ljava/lang/String;ILjava/lang/String;)V
PUTSTATIC com/whiteship/white_ship_study/week11/Week.SUNDAY : Lcom/whiteship/white_ship_study/week11/Week;
L7
LINENUMBER 3 L7
BIPUSH 7
ANEWARRAY com/whiteship/white_ship_study/week11/Week
DUP
ICONST_0
GETSTATIC com/whiteship/white_ship_study/week11/Week.MONDAY : Lcom/whiteship/white_ship_study/week11/Week;
AASTORE
DUP
ICONST_1
GETSTATIC com/whiteship/white_ship_study/week11/Week.TUESDAY : Lcom/whiteship/white_ship_study/week11/Week;
AASTORE
DUP
ICONST_2
GETSTATIC com/whiteship/white_ship_study/week11/Week.WEDNESDAY : Lcom/whiteship/white_ship_study/week11/Week;
AASTORE
DUP
ICONST_3
GETSTATIC com/whiteship/white_ship_study/week11/Week.THURSDAY : Lcom/whiteship/white_ship_study/week11/Week;
AASTORE
DUP
ICONST_4
GETSTATIC com/whiteship/white_ship_study/week11/Week.FRIDAY : Lcom/whiteship/white_ship_study/week11/Week;
AASTORE
DUP
ICONST_5
GETSTATIC com/whiteship/white_ship_study/week11/Week.SATURDAY : Lcom/whiteship/white_ship_study/week11/Week;
AASTORE
DUP
BIPUSH 6
GETSTATIC com/whiteship/white_ship_study/week11/Week.SUNDAY : Lcom/whiteship/white_ship_study/week11/Week;
AASTORE
PUTSTATIC com/whiteship/white_ship_study/week11/Week.$VALUES : [Lcom/whiteship/white_ship_study/week11/Week;
RETURN
MAXSTACK = 5
MAXLOCALS = 0
}
1. java.lang.Enum 을 상속받는다.
public final enum com/whiteship/white_ship_study/week11/EnumEx extends java/lang/Enum {
제일 첫 부분이다.
그렇다. enum 클래스는 컴파일타임에 자동으로 java.lang.Enum 클래스를 상속받고 있다.
따라서 enum 클래스는 상속이 되지 않고, Enum 클래스에 정의된 함수들을 사용 가능하다.
2. enum 상수들은 객체이다.
public final static enum Lcom/whiteship/white_ship_study/week11/Week; MONDAY
이 부분은 우리가 정의한 enum 안의 상수다.
public final static 을 사용하지 않았지만, 자동으로 모두 붙어 있다.
상수를 정의하던 것과 같다.
또한, EnumEx 형으로 만들어진 객체임을 알 수 있다.
따라서 우리는 이 상수 객체에 생성자를 만들 수 있고, 값을 가질 수 있고, 메서드를 가질 수 있게 할 수 있는 것이다.
3. enum 생성자는 private 이다.
private <init>(Ljava/lang/String;ILjava/lang/String;)V
우리는 private으로 지정한 적 이 없는데 private 이다.
enum 은 고정된 상수 집합이라 하였다.
따라서 런타임에 우리는 이 enum 으로 객체를 만들면 안된다. 쉽게말해, 런타임시에 값이 바뀌면 안된다.
객체를 만들지 않게 하는 방법이 private 생성자만 제공하는 방법이다.
외부에서 접근할 수 있는 생성자가 없다면, 객체를 생성할 수 없다.
따라서 enum 의 모든 생성자에는 private 이 자동으로 붙는다.
또한 생성자가 없으면 enum 클래스를 상속할 수 도 없다.
이러한 특성 때문에 enum 은 싱글톤을 구현하는 이상적인 방법이 될 수 있기도 하다. (effective java)
바이트코드에서 알 수있는 정보는 몇가지 더 있는데, 이후 관련 블럭에서 알아보자.
Enum 이 제공하는 메서드
- enum 타입은 자동으로 java.lang.Enum 을 상속받는다고 했다.
- 그렇다면 우리는 Enum 에 정의된 함수들을 알아야 enum 상수들을 재대로 쓸 수 있다.
name 필드
- Enum 클래스에는 name 이라는 필드가 있다.
- 또 toString() 에는 return name을 하고 있다.
- Enum 클래스에는 생성자가 하나 있는데 모양은 이렇다. (ordinal 은 순서이다.)
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
그리고 위의 바이트코드의 생성자 부분을 다시 보자.
private <init>(Ljava/lang/String;ILjava/lang/String;)V
// parameter synthetic $enum$name
// parameter synthetic $enum$ordinal
// parameter korean
enum 의 name, ordinal 이 컴파일하면서 자동으로 파라미터로 들어간다.
(synthetic 이 붙은 것은 컴파일타임에 자동으로 들어간다는 뜻 같다.. 확실하게는 모름)
그렇게 되면 우리가 정의한 생성자를 보면,
EnumEx(String korean) {
this.korean = korean;
}
이 모양인데, name과 ordinal 은 아래와 같이 들어가는 것이다.
EnumEx(String korean) {
super(name, ordinal);
this.korean = korean;
}
따라서, 우리가 정의한 enum 상수들은 우리가 정의한 인스턴스 필드와 name, ordinal 을 속성으로 가지게 되는 것이다.
name 은 enum 에 정의한 상수명이고, ordinal 은 상수를 여러개 선언했을때 각각의 순서이다.
name(), toString()
public String name() {
return name;
}
public String toString() {
return name;
}
쉽다. name 반환.
static E valueOf()
- valueOf() 는 static 메서드이다.
- 리턴 타입은 enum 상수이다.
- 매개변수로 String 을 받아서 그 이름과 같은 enum 상수 객체를 리턴한다.
public class ValueOf {
public static void main(String[] args) {
Week today = Week.valueOf("FRIDAY");
System.out.println(today);
System.out.println(today.getWeekKorean());
}
}
static E values()
- values() 도 static 메서드이다.
- 해당 enum의 배열을 리턴한다.
public class values {
public static void main(String[] args) {
Week[] weeks = Week.values();
for (Week week : weeks) {
System.out.println(week.getWeekKorean());
}
}
}
values(), valueOf() 가 없다?
- enum은 Enum 클래스를 상속받아 위와같은 메서드를 쓸 수 있을 것 같지만, 정작 Enum 클래스를 열어보면 이 메서드들이 없다.
- valueOf() 는 있지만, 메서드 시그니쳐가 다르다.
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
그렇다면 이 메서드들은 어디서 난 것일까.
이 정답도 바이트코드에 있다.
// access flags 0x101A
private final static synthetic [Lcom/whiteship/white_ship_study/week11/Week; $VALUES
// access flags 0x9
public static values()[Lcom/whiteship/white_ship_study/week11/Week;
L0
LINENUMBER 3 L0
GETSTATIC com/whiteship/white_ship_study/week11/Week.$VALUES : [Lcom/whiteship/white_ship_study/week11/Week;
INVOKEVIRTUAL [Lcom/whiteship/white_ship_study/week11/Week;.clone ()Ljava/lang/Object;
CHECKCAST [Lcom/whiteship/white_ship_study/week11/Week;
ARETURN
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x9
public static valueOf(Ljava/lang/String;)Lcom/whiteship/white_ship_study/week11/Week;
// parameter mandated name
L0
LINENUMBER 3 L0
LDC Lcom/whiteship/white_ship_study/week11/Week;.class
ALOAD 0
INVOKESTATIC java/lang/Enum.valueOf (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
CHECKCAST com/whiteship/white_ship_study/week11/Week
ARETURN
L1
LOCALVARIABLE name Ljava/lang/String; L0 L1 0
MAXSTACK = 2
MAXLOCALS = 1
- VALUES 라는 private 인스턴스 변수를 컴파일타임에 자동으로 생성한다.
- 그리고 선언하지도 않았던 values() 에서 이 인스턴스 변수를 이용하여 메서드를 만들고 있다.
- 그 아래에는 선언하지 않았던 valueOf() 를 만들고, String 인자를 받아서, Enum 클래스의 valueOf를 자신 객체를 더해서 호출한다.
- 두 메서드 모두 public static 으로 선언되어 우리가 사용할 수 있는 것이다.
결론 : 모든 enum 타입은 values, valueOf 가 컴파일타임에 자동으로 만들어 진다.
Clone()
- Object 클래스는 모든 클래스의 조상이므로 enum 도 clone 이 있을 것이다.
- 하지만 enum 은 상수로써, private 생성자로 객체생성도 막는데, clone() 를 제공하면 안된다.
- 그래서 오버라이딩하여 예외를 던지도록 구현해놨더라.
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
public
class CloneNotSupportedException extends Exception {
private static final long serialVersionUID = 5195511250079656443L;
/**
* Constructs a <code>CloneNotSupportedException</code> with no
* detail message.
*/
public CloneNotSupportedException() {
super();
}
/**
* Constructs a <code>CloneNotSupportedException</code> with the
* specified detail message.
*
* @param s the detail message.
*/
public CloneNotSupportedException(String s) {
super(s);
}
}
Exception 을 상속받은 checked 예외다.
Ordinal()
- 여러개의 상수가 enum에 정의되었다 치자.
- 각 상수는 정의한 물리적인 순서가 있을 것이다.
- 이 물리적인 순서를 가져오는 메서드이다.
- 하지만 이 메서드에는 문제가 있는데, 물리적인 순서는 새로운 상수가 추가되고, 없어지고 함에 따라 바뀔 수 있다는 것이다.
- 따라서 이 메서드는 사용하면 안되는 메서드이다.
public class OrdinalEx {
public static void main(String[] args) {
Week[] weeks = Week.values();
for (Week week : weeks) {
System.out.println(week.name() + " : " + week.ordinal());
}
}
}
여기서 처음에 다른 날이 추가되면 ?
모든 요일의 순서가 달라졌으므로 출력 순서도 달라진다.
따라서 순서를 나타내는 필드를 새로 두기도 하는데, 선장님의 팁으로는
순서를 10, 20, 30 처럼 띄엄띄엄 지정해놔야 중간에 새로운 상수가 추가되더라도 순서를 지정하기쉽다.
EnumSet
- enum과 함께 사용하기 위한 특별한 Set의 구현체이다.
- EnumSet 에 정의된 모든 메서드는 static 이다.
- enum 의 상수들을 Set 으로 만들 수 있는 편리한 기능들을 제공한다.
- 생성자는 없다.
EnumSet - noneOf(Class<E> elementType)
- 매개변수로 받은 요소 타입을 사용하여 비어있는 EnumSet을 만든다.
public class EnumSetEx {
public static void main(String[] args) {
EnumSet<Week> w = EnumSet.noneOf(Week.class);
System.out.println(w.size());
}
}
// 출력값 0
EnumSet - AllOf(Class<E> elementType)
- 매개변수로 받은 요소 타입을 사용하여 모든 상수를 가진 EnumSet을 만든다.
public class EnumSetEx {
public static void main(String[] args) {
EnumSet<Week> w = EnumSet.allOf(Week.class);
w.stream().forEach(System.out::println);
}
}
EnumSet - of(E e1)
- 어떤 요소가 들어갈지 결정할 수 있다.
- 5개까지의 인자가 들어갈 수 있도록 오버로딩 되어 있고, 6개부터는 가변인자를 이용하여 오버로딩했다.
- 제네릭에 선언한 타입의 enum 상수들을 매개변수로 넣는다.
public class EnumSetEx {
public static void main(String[] args) {
EnumSet<Week> w = EnumSet.of(Week.FRIDAY, Week.SUNDAY);
w.stream().forEach(System.out::println);
}
}
EnumSet - complementOf(EnumSet<E> s)
- 매개변수 set 이 포함되지 않은 set을 만든다.
public class Complementof {
public static void main(String[] args) {
EnumSet<Week> Monday = EnumSet.of(Week.MONDAY);
EnumSet<Week> weeks = EnumSet.complementOf(Monday);
for (Week week : weeks) {
System.out.println(week);
}
}
}
결과는 월요일만 뺀 요일들이 출력된다.
이 메서드는 어떻게 Week의 모든 상수를 알고 거기서 Monday를 빼준걸까.
Enum의 인스턴스 변수에는 universe 라는 것이 있다.
이 변수에는 Enum 생성시 enum의 모든 상수가 들어가 있다.
API 설명에는 퍼포먼스 향상을 위한 캐시 데이터라는데, 이런 곳에 쓰이는 것이다.
EnumSet에는 왜 생성자가 없는가?
- 원소가 적을 때 사용하는 RegularEnumSet, 원소가 많을 때 사용하는 JumboEnumSet이라는 구현체들이 존재하고, 이 클래스에서 상수의 개수에 따라 다른 구현체로 객체를 생성하게 할 수 있다.
- 원소의 초기화를 간편하게 할 수 있다.
- RegularEnumSet, JumboEnumSet 이외에 다른 구현체가 새로 추가된다 하여도, 기존 클라이언트 코드에는 영향을 주지 않는다. 확장성이 좋다는 말이다.
마지막 - enum의 장점
- IDE의 지원을 받을 수 있다 - 자동완성, 오타검증 등
- 값을 제한할 수 있다 - 예를 들어 매개변수로 특정한 객체들만 들어갈 수 있을 떄, enum을 사용하면 enum에 정의되지 않은 상수는 컴파일타임에 오류를 표출한다.
- 리펙토링이 좋다 - 상수 및 생성자, 메서드를 모아 놓았으므로 리펙터링시 해당 enum만 변경하면 된다.
마지막의 마지막 - enum 활용의 하나
- abstract 메서드를 선언하므로써 상수 객체마다 각자의 동작을 할 수 있게 만들 수 있다.
- 람다식과 함수형 인터페이스를 이용해서도 가능한데, 저번에 작성한 나의 글을 첨부한다.
참고 :
effective Java 3E
www.notion.so/Enum-6ffa87530c424d8ab7a1b585bfb26fa2
'WhiteShip Java Study : 자바 처음부터 멀리까지' 카테고리의 다른 글
ServiceLoader (0) | 2021.02.14 |
---|---|
Annotation (0) | 2021.02.13 |
멀티스레드 프로그래밍 (0) | 2021.02.06 |
예외 처리 (0) | 2021.02.05 |
인터페이스 (0) | 2021.02.04 |