Enum은 Java 1.5에서 도입된 새로운 타입으로, 필드는 고정된 상수 집합으로 구성됩니다. 예를 들어, 우리는 동, 서, 남, 북과 같은 고정된 필드를 가진 Java Enum으로 방향을 생성할 수 있습니다.
Java Enum
이 튜토리얼에서는 Enum을 생성하는 방법을 배우게 될 것입니다. 또한 Java에서 Enum을 사용하는 이점과 Enum 타입의 특징에 대해 알아볼 것입니다. 또한 Java Enum의
valueOf
, enum values
, EnumSet
및 EnumMap
을 예제와 함께 사용하는 방법도 배우게 될 것입니다.
Java Enum 예제
Java enum 키워드는 enum 타입을 생성하는 데 사용됩니다. Java enum 예제 프로그램을 살펴보겠습니다.
package com.journaldev.enums;
public enum ThreadStates {
START,
RUNNING,
WAITING,
DEAD;
}
위의 예제에서 ThreadStates는 START, RUNNING, WAITING 및 DEAD와 같은 고정된 상수 필드를 가진 enum입니다.
Java Enum vs 상수
이제 Java 클래스의 일반적인 상수 필드보다 Java enum이 더 우수한지 살펴보겠습니다. 비슷한 상수 클래스를 Java에서 생성해보겠습니다.
package com.journaldev.enums;
public class ThreadStatesConstant {
public static final int START = 1;
public static final int WAITING = 2;
public static final int RUNNING = 3;
public static final int DEAD = 4;
}
이제 자바 프로그램에서 enum 및 상수가 어떻게 사용되는지 살펴보겠습니다.
/**
* This method shows the benefit of using Enum over Constants
*/
private static void benefitsOfEnumOverConstants() {
//Enum 값은 고정됩니다
simpleEnumExample(ThreadStates.START);
simpleEnumExample(ThreadStates.WAITING);
simpleEnumExample(ThreadStates.RUNNING);
simpleEnumExample(ThreadStates.DEAD);
simpleEnumExample(null);
simpleConstantsExample(1);
simpleConstantsExample(2);
simpleConstantsExample(3);
simpleConstantsExample(4);
//우리는 임의의 int 상수를 전달할 수 있습니다
simpleConstantsExample(5);
}
private static void simpleEnumExample(ThreadStates th) {
if(th == ThreadStates.START) System.out.println("Thread started");
else if (th == ThreadStates.WAITING) System.out.println("Thread is waiting");
else if (th == ThreadStates.RUNNING) System.out.println("Thread is running");
else System.out.println("Thread is dead");
}
private static void simpleConstantsExample(int i) {
if(i == ThreadStatesConstant.START) System.out.println("Thread started");
else if (i == ThreadStatesConstant.WAITING) System.out.println("Thread is waiting");
else if (i == ThreadStatesConstant.RUNNING) System.out.println("Thread is running");
else System.out.println("Thread is dead");
}
위의 예제를 살펴보면, 상수 사용에 따른 두 가지 위험이 있으며 이는 enum으로 해결됩니다.
- 우리는
simpleConstantsExample
메서드에 임의의 int 상수를 전달할 수 있지만 simpleEnumExample에는 고정된 값만 전달할 수 있으므로 이는 형식 안정성을 제공합니다. ThreadStatesConstant
클래스에서 int 상수 값을 변경할 수 있지만 위의 프로그램은 예외를 throw하지 않습니다. 우리의 프로그램은 예상대로 작동하지 않을 수 있지만 enum 상수를 변경하면 컴파일 시간 오류가 발생하여 런타임 문제의 가능성을 제거합니다.
자바 Enum 메서드
이제 예제와 함께 자바 enum의 더 많은 기능을 살펴보겠습니다.
package com.journaldev.enums;
import java.io.Closeable;
import java.io.IOException;
/**
* This Enum example shows all the things we can do with Enum types
*
*/
public enum ThreadStatesEnum implements Closeable{
START(1){
@Override
public String toString(){
return "START implementation. Priority="+getPriority();
}
@Override
public String getDetail() {
return "START";
}
},
RUNNING(2){
@Override
public String getDetail() {
return "RUNNING";
}
},
WAITING(3){
@Override
public String getDetail() {
return "WAITING";
}
},
DEAD(4){
@Override
public String getDetail() {
return "DEAD";
}
};
private int priority;
public abstract String getDetail();
//Enum 생성자는 항상 private여야 합니다.
private ThreadStatesEnum(int i){
priority = i;
}
//Enum에는 메서드를 가질 수 있습니다
public int getPriority(){
return this.priority;
}
public void setPriority(int p){
this.priority = p;
}
//Enum은 함수를 오버라이드할 수 있습니다
@Override
public String toString(){
return "Default ThreadStatesConstructors implementation. Priority="+getPriority();
}
@Override
public void close() throws IOException {
System.out.println("Close of Enum");
}
}
자바 Enum 중요 포인트
자바에서 Enums의 중요한 몇 가지 포인트는 다음과 같습니다.
- 모든 Java enum은 암시적으로
java.lang.Enum
클래스를 확장하며, 이 클래스는 Object 클래스를 확장하고 Serializable 및 Comparable 인터페이스를 구현합니다. 따라서 enum에서는 어떤 클래스도 확장할 수 없습니다. - enum은 키워드이므로 패키지 이름을 이로 끝낼 수 없습니다. 예를 들어
com.journaldev.enum
은(는) 유효한 패키지 이름이 아닙니다. - Enum은 인터페이스를 구현할 수 있습니다. 위의 enum 예제에서는
Closeable
인터페이스를 구현하고 있습니다. - Enum 생성자는 항상 private입니다.
- new 연산자를 사용하여 enum의 인스턴스를 생성할 수 없습니다.
- Java enum에서 추상 메서드를 선언할 수 있으며, 그러면 모든 enum 필드가 추상 메서드를 구현해야 합니다. 위의 예에서
getDetail()
는 추상 메서드이며 모든 enum 필드가 이를 구현했습니다. - Enum에 메서드를 정의할 수 있으며 enum 필드는 이를 재정의할 수 있습니다. 예를 들어
toString()
메서드가 enum에서 정의되어 있고 enum 필드 START가 이를 재정의했습니다. - Java enum 필드에는 네임스페이스가 있으며,
ThreadStates.START
와 같이 클래스 이름으로만 enum 필드를 사용할 수 있습니다. - Enums는 switch 문에서 사용할 수 있으며, 이 튜토리얼의 나중 부분에서 실제 사용 사례를 살펴볼 것입니다.
- 우리는 기존 기능을 손상시키지 않고 기존 열거형을 확장할 수 있습니다. 예를 들어, ThreadStates 열거형에 새로운 필드 NEW를 추가할 수 있습니다.
- 열거형 필드는 상수이므로 Java에서는 블록 문자와 밑줄을 사용하여 작성하는 것이 좋은 관례입니다. 예를 들어, EAST, WEST, EAST_DIRECTION 등입니다.
- 열거형 상수는 암시적으로 static과 final입니다.
- 열거형 상수는 final이지만 해당 변수를 변경할 수 있습니다. 예를 들어, setPriority() 메서드를 사용하여 열거형 상수의 우선 순위를 변경할 수 있습니다. 아래 예제에서 사용 예를 살펴보겠습니다.
- 열거형 상수가 final이므로 “==” 및 equals() 메서드를 사용하여 안전하게 비교할 수 있습니다. 두 가지 방법 모두 같은 결과를 갖습니다.
Java EnumSet, EnumMap, valueOf()
이제 열거형의 대부분의 기능을 알았으니 Java Enum 예제 프로그램을 살펴보겠습니다. 그런 다음 열거형의 몇 가지 기능을 더 배우겠습니다.
package com.journaldev.enums;
import java.io.IOException;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Set;
public class JavaEnumExamples {
public static void main(String[] args) throws IOException {
usingEnumMethods();
usingEnumValueOf();
usingEnumValues();
usingEnumInSwitch(ThreadStatesEnum.START);
usingEnumInSwitch(ThreadStatesEnum.DEAD);
usingEnumMap();
usingEnumSet();
}
private static void usingEnumSet() {
EnumSet enumSet = EnumSet.allOf(ThreadStatesEnum.class);
for(ThreadStatesEnum tsenum : enumSet){
System.out.println("Using EnumSet, priority = "+tsenum.getPriority());
}
}
private static void usingEnumMap() {
EnumMap<ThreadStatesEnum, String> enumMap = new EnumMap<ThreadStatesEnum,String>(ThreadStatesEnum.class);
enumMap.put(ThreadStatesEnum.START, "Thread is started");
enumMap.put(ThreadStatesEnum.RUNNING, "Thread is running");
enumMap.put(ThreadStatesEnum.WAITING, "Thread is waiting");
enumMap.put(ThreadStatesEnum.DEAD, "Thread is dead");
Set keySet = enumMap.keySet();
for(ThreadStatesEnum key : keySet){
System.out.println("key="+key.toString()+":: value="+enumMap.get(key));
}
}
private static void usingEnumInSwitch(ThreadStatesEnum th) {
switch (th){
case START:
System.out.println("START thread");
break;
case WAITING:
System.out.println("WAITING thread");
break;
case RUNNING:
System.out.println("RUNNING thread");
break;
case DEAD:
System.out.println("DEAD thread");
}
}
private static void usingEnumValues() {
ThreadStatesEnum[] thArray = ThreadStatesEnum.values();
for(ThreadStatesEnum th : thArray){
System.out.println(th.toString() + "::priority="+th.getPriority());
}
}
private static void usingEnumValueOf() {
ThreadStatesEnum th = Enum.valueOf(ThreadStatesEnum.class, "START");
System.out.println("th priority="+th.getPriority());
}
private static void usingEnumMethods() throws IOException {
ThreadStatesEnum thc = ThreadStatesEnum.DEAD;
System.out.println("priority is:"+thc.getPriority());
thc = ThreadStatesEnum.DEAD;
System.out.println("Using overriden method."+thc.toString());
thc = ThreadStatesEnum.START;
System.out.println("Using overriden method."+thc.toString());
thc.setPriority(10);
System.out.println("Enum Constant variable changed priority value="+thc.getPriority());
thc.close();
}
}
열거형의 다른 중요한 기능을 설명하기 전에 위의 프로그램의 출력을 살펴보겠습니다.
priority is:4
Using overriden method.Default ThreadStatesConstructors implementation. Priority=4
Using overriden method.START implementation. Priority=1
Enum Constant variable changed priority value=10
Close of Enum
th priority=10
START implementation. Priority=10::priority=10
Default ThreadStatesConstructors implementation. Priority=2::priority=2
Default ThreadStatesConstructors implementation. Priority=3::priority=3
Default ThreadStatesConstructors implementation. Priority=4::priority=4
START thread
DEAD thread
key=START:: value=Thread is started
key=RUNNING:: value=Thread is running
key=WAITING:: value=Thread is waiting
key=DEAD:: value=Thread is dead
Using EnumSet, priority = 10
Using EnumSet, priority = 2
Using EnumSet, priority = 3
Using EnumSet, priority = 4
중요한 점
usingEnumMethods()
메서드는 열거형 객체를 생성하는 방법과 해당 메서드를 사용하는 방법을 보여줍니다. 또한 열거형 변수를 변경하기 위한setPriority(int i)
메서드의 사용법을 보여줍니다.usingEnumValueOf()
는 문자열에서 열거형 객체를 생성하는 방법을 보여줍니다. 이를 위해java.util.Enum
의valueOf(enumType, name)
을 사용합니다. 지정된 열거형 유형에 지정된 이름을 가진 상수가 없거나 지정된 클래스 객체가 열거형 유형을 나타내지 않는 경우IllegalArgumentException
을 throw합니다. 또한 인수 중 하나가 null인 경우NullPointerException
을 throw합니다.usingEnumValues()
메서드는 열거형의 모든 값을 포함하는 배열을 반환하는 values() 메서드의 사용법을 보여줍니다. 이 메서드는 모든 열거형에 대해 자동으로 생성되며java.util.Enum
클래스에는 values() 구현이 없습니다.usingEnumInSwitch()
메서드는 switch case에서 열거형 상수를 사용하는 방법을 보여줍니다.usingEnumMap()
메서드는 Java 1.5 Collections Framework에서 소개된 java.util.EnumMap의 사용법을 보여줍니다.EnumMap
은 열거형 키와 함께 사용하는 Map 구현체입니다. 열거형 맵의 모든 키는 맵이 생성될 때 명시적 또는 암시적으로 지정된 단일 열거형 유형에서 가져와야 합니다. EnumMap에는 키로 null을 사용할 수 없으며 EnumMap은 동기화되지 않습니다.usingEnumSet()
메서드는 java.util.EnumSet을 사용하여 enum 유형과 함께 사용하는 Set 구현을 보여줍니다. Enum set의 모든 요소는 집합이 생성될 때 명시적 또는 암시적으로 지정된 단일 enum 유형에서 가져와야 합니다. EnumSet은 동기화되지 않으며 null 요소는 허용되지 않습니다. 또한copyOf(Collection<E> c)
,of(E first, E... rest)
,complementOf(EnumSet<E> s)
와 같은 유용한 메서드를 제공합니다.
모든 예제는 GitHub 저장소에서 확인할 수 있습니다.
참고: Oracle 문서
Source:
https://www.digitalocean.com/community/tutorials/java-enum