오늘은 Java 에서 은근히 많이 활용하는 Enum 을 소개합니다.
개요
Java 5는 처음으로 enum 키워드를 도입했습니다. 항상 java.lang.Enum 클래스 를 확장하는 특수한 유형의 클래스를 나타냅니다 .
이러한 방식으로 정의된 상수는 코드를 더 읽기 쉽게 만들고, 컴파일 시간 확인을 허용하고, 허용되는 값 목록을 미리 문서화하고, 잘못된 값이 전달되어 예기치 않은 동작을 방지합니다.
다음은 피자 주문 상태를 정의하는 열거형의 빠르고 간단한 예입니다. 주문 상태는 ORDERED , READY 또는 DELIVERED 일 수 있습니다 .
public enum PizzaStatus {
ORDERED,
READY,
DELIVERED;
}
사용자 지정 열거형 메서드
열거형이 무엇이고 어떻게 사용할 수 있는지에 대한 기본적인 이해를 하였으므로 열거형에 대한 몇 가지 추가 API 메서드를 정의하여 이전 예제를 다음 단계로 넘어갈 것입니다.
public class Pizza {
private PizzaStatus status;
public enum PizzaStatus {
ORDERED,
READY,
DELIVERED;
}
public boolean isDeliverable() {
if (getStatus() == PizzaStatus.READY) {
return true;
}
return false;
}
// Methods that set and get the status variable.
}
"==" 연산자를 사용한 열거형 비교
열거형 유형은 JVM에 하나의 상수 인스턴스만 존재하도록 보장하므로 위의 예에서와 같이 "==" 연산자를 사용하여 두 변수를 안전하게 비교할 수 있습니다. 또한 "==" 연산자는 컴파일 시간 및 런타임 안전성을 제공합니다.
먼저 다음 스니펫 에서 런타임 안전성 을 살펴 보겠습니다. 여기서 "==" 연산자를 사용하여 상태를 비교합니다. 두 값 모두 null 일 수 있으며 NullPointerException이 발생 하지 않습니다 . 반대로 equals 메서드를 사용하면 NullPointerException 이 발생합니다 .
if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED));
if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED);
컴파일 시간 안전성 에 관해서 는 equals 메서드 를 사용하여 비교하여 다른 유형의 열거형이 동일한지 확인하는 예제를 살펴보겠습니다 . enum과 getStatus 메소드의 값이 우연히 동일하기 때문입니다. 그러나 논리적으로 비교는 거짓이어야 합니다. "==" 연산자를 사용하여 이 문제를 방지합니다.
컴파일러는 비교를 비호환성 오류로 플래그 지정합니다.
if(testPz.getStatus().equals(TestColor.GREEN));
if(testPz.getStatus() == TestColor.GREEN);
Switch 문에서 열거형 사용하기
switch 문 에서 열거형 유형을 사용할 수도 있습니다.
public int getDeliveryTimeInDays() {
switch (status) {
case ORDERED: return 5;
case READY: return 2;
case DELIVERED: return 0;
}
return 0;
}
열거형의 필드, 메서드 및 생성자
열거형 내부에 생성자, 메서드 및 필드를 정의할 수 있으므로 매우 강력합니다.
다음으로 피자 주문의 한 단계에서 다른 단계로의 전환을 구현하여 위의 예를 확장해 보겠습니다. 이전에 사용된 if 및 switch 문 을 제거하는 방법을 살펴보겠습니다 .
public class Pizza {
private PizzaStatus status;
public enum PizzaStatus {
ORDERED (5){
@Override
public boolean isOrdered() {
return true;
}
},
READY (2){
@Override
public boolean isReady() {
return true;
}
},
DELIVERED (0){
@Override
public boolean isDelivered() {
return true;
}
};
private int timeToDelivery;
public boolean isOrdered() {return false;}
public boolean isReady() {return false;}
public boolean isDelivered(){return false;}
public int getTimeToDelivery() {
return timeToDelivery;
}
PizzaStatus (int timeToDelivery) {
this.timeToDelivery = timeToDelivery;
}
}
public boolean isDeliverable() {
return this.status.isReady();
}
public void printTimeToDeliver() {
System.out.println("Time to delivery is " +
this.getStatus().getTimeToDelivery());
}
// Methods that set and get the status variable.
}
아래의 테스트 스니펫은 이것이 어떻게 작동하는지 보여줍니다
@Test
public void givenPizaOrder_whenReady_thenDeliverable() {
Pizza testPz = new Pizza();
testPz.setStatus(Pizza.PizzaStatus.READY);
assertTrue(testPz.isDeliverable());
}
자바 8과 열거형
Java 8에서 Pizza 클래스를 다시 작성할 수 있으며 람다 및 Stream API 를 사용하여 getAllUndeliveredPizzas() 및 groupPizzaByStatus( ) 메서드가 얼마나 간결해졌는지 확인할 수 있습니다.
public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
return input.stream().filter(
(s) -> !deliveredPizzaStatuses.contains(s.getStatus()))
.collect(Collectors.toList());
}
public static EnumMap<PizzaStatus, List<Pizza>>
groupPizzaByStatus(List<Pizza> pzList) {
EnumMap<PizzaStatus, List<Pizza>> map = pzList.stream().collect(
Collectors.groupingBy(Pizza::getStatus,
() -> new EnumMap<>(PizzaStatus.class), Collectors.toList()));
return map;
}
Enum의 JSON 표
Jackson 라이브러리를 사용하면 POJO인 것처럼 열거형 유형의 JSON 표현을 가질 수 있습니다. 아래 코드 스니펫에서 동일한 항목에 대해 Jackson 주석을 사용하는 방법을 확인할 수 있습니다.
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum PizzaStatus {
ORDERED (5){
@Override
public boolean isOrdered() {
return true;
}
},
READY (2){
@Override
public boolean isReady() {
return true;
}
},
DELIVERED (0){
@Override
public boolean isDelivered() {
return true;
}
};
private int timeToDelivery;
public boolean isOrdered() {return false;}
public boolean isReady() {return false;}
public boolean isDelivered(){return false;}
@JsonProperty("timeToDelivery")
public int getTimeToDelivery() {
return timeToDelivery;
}
private PizzaStatus (int timeToDelivery) {
this.timeToDelivery = timeToDelivery;
}
}
다음과 같이 Pizza 및 PizzaStatus 를 사용할 수 있습니다 .
Pizza pz = new Pizza();
pz.setStatus(Pizza.PizzaStatus.READY);
System.out.println(Pizza.getJsonString(pz));
그러면 Pizza 상태에 대한 다음 JSON 표현이 생성됩니다.
{
"status" : {
"timeToDelivery" : 2,
"ready" : true,
"ordered" : false,
"delivered" : false
},
"deliverable" : true
}
열거형 유형의 JSON 직렬화/역직렬화(사용자 정의 포함)에 대한 자세한 내용은 Jackson – 직렬화 열거형을 JSON 개체로 참조할 수 있습니다 .
댓글