키 값만으로 enum 객체를 얻는 방법
Updated:
1. 일반적인 enum 클래스 사용법
여기 MissionInfo 라는 enum 클래스가 있다.
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum MissionInfo {
Tick_1Day(1, 10),
Tick_3Day(3, 60),
Quick_5Day(5, 150),
Quick_7Day(7, 280),
Huick_15Day(15, 100),
Huick_30Day(30, 300);
private final int missionType;
private final int rewardPoint;
}
보통 여기서 값을 꺼낼 때는 이와 같이 꺼내서 사용할 것이다.
MissionInfo.Tick_1Day.getMissionType();
MissionInfo.Quick_5Day.getRewardPoint();
2. 키 값만으로 enum 객체를 얻는 방법
그런데 만약 missionType 값이 유니크하고, 이 값을 통해서 enum 클래스를 리턴 받고 싶다면 어떻게 할까?
enum 클래스를 Map 형태로 가지고 있으면 검색하기 쉬워질 것 같다!
enum 클래스 아래쪽에 Map<Integer, Object> 타입으로 변수를 선언해보자
private static final Map<Integer, MissionInfo> codes = Collections.unmodifiableMap(
Stream.of(values()).collect(Collectors.toMap(MissionInfo::getMissionType, Function.identity())));
values() 를 통해 MissionInfo 배열을 받아서 Stream.of 로 순차 스트림을 만든다.
collect()를 통해 missionType을 키로 사용하고, MissionInfo를 값으로 사용하는 Map 형태의 자료형을 만든다.
여기서 Function.identity()는 전달받은 파라미터인 MissionInfo를 뜻한다.
이렇게 리턴된 Map을 Collections.unmodifiableMap() 으로 감싸는데는 이유가 있다.
바로 변조될 위험이 없는 read-only 변수를 만들기 위함이다.
만약 해당 Map에 put, remove, putAll 함수를 호출하게 되면 UnsupportedOperationException 예외가 발생되도록 설계되어 있다.
java.lang.UnsupportedOperationException
at java.base/java.util.Collections$UnmodifiableMap.put(Collections.java:1457)
변수를 선언하였으니, 외부에서 사용 가능하도록 public 변수를 하나 만들어 준다. 이제는 키값만 알면 enum 객체를 얻을 수 있다. 참으로 편리하다!
public static MissionInfo find(int missionType) {
return Optional.ofNullable(codes.get(missionType)).orElse(null);
}
3. 키 값이 중복되거나, 그룹핑이 필요한 경우
위와 같은 MissionInfo는 키 값이 중복되지 않아서 문제되진 않겠지만
만약 키가 중복된다면 어떨까?
Tick_1Day(1, 10),
Tick_3Day(1, 60),
Quick_5Day(1, 150),
Quick_7Day(7, 280),
Huick_15Day(15, 100),
Huick_30Day(30, 300);
실행하게 되면 아래처럼 ExceptionInInitializerError 오류가 발생한다.
중복 키가 발생했기 때문이다.
java.lang.ExceptionInInitializerError
Caused by: java.lang.IllegalStateException: Duplicate key 1 (attempted merging values Tick_1Day and Tick_3Day)
중복 키가 발생한다면, 임의의 규칙을 정하여 한개만 저장되게 하면 될 것이다.
Collectors.toMap 세번째 인자에 merge function을 정의한다.
예제에서는 두 객체 중 첫번째 객체를 사용하도록 했다.
그러면 MissionInfo.find 시, Tick_1Day 값을 리턴할 것이다.
반대로 (a, b) -> b 로 정의했다면, Quick_5Day 값을 리턴할 것이다.
public static final Map<Integer, MissionInfo> codes = Collections.unmodifiableMap(
Stream.of(values()).collect(Collectors.toMap(MissionInfo::getMissionType, Function.identity(), (a, b) -> a)));
그리고 중복 제거가 아닌 그룹핑하여 Map을 만들고 싶을때도 있다.
Collectors.groupingBy()를 사용하여 키는 missionType, 값은 List
public static final Map<Integer, List<MissionInfo>> codes =
Stream.of(values()).collect(Collectors.groupingBy(MissionInfo::getMissionType));
중복이나, 그룹핑은 생각하지 못했는데
글 작성을 위하여 구글링을 좀 하다가 좋은 정보를 얻게되었다!
매우 뿌듯하다!
Leave a comment