class Plant {
enum LifeCycle {ANNUAL, PEREMINAL, BIENNIAL}
final String name;
final LifeCycle lifeCycle;
Plant(String name, LifeCycle lifeCycle) {
this.name = name;
this.lifeCycle = lifeCycle;
}
@Override public String toString() {
return name;
}
}
/**
* 방법 1
**/
Map<Plant.LifeCycle, Set<Plant>> platnsByLifeCycle =
new EnumMap<>(Plant.LifeCycle.class);
for (Plant.LifeCycle lc : Plant.LifeCycle.values())
plantsByLifeCycle.put(lc, new HashSet<>());
for (Plant p : garden)
plantsByLifeCycle.get(p.lifeCycle).add(p);
System.out.println(plantsByLifeCycle);
/**
* 방법 2 - 1.
**/
System.out.println(Arrays.stream(garden)
.collect(groupingBy(p -> p.lifeCycle));
/**
* 방법 2 - 2
**/
System.out.println(Arrays.stream(garden)
.collect(groupingBy(p -> p.lifeCycle,
() -> new EnumMap<>(LifeCycle.class), toSet())));
방법 1과 방법 2 - * 의 차이는 방법 1은 모든 enum type 에 대해서 set을 생성한다는 것이고 , 방법 2는 garden에 있는 enum type만을 set을 생성한다는 것이다.
stream
을 사용한 방법2는 방법1보다 간결하지만 overhead
가 발생할 수 있다. 하지만 parallel processing
을 통해 성능을 끌어낼 수 있다.
EnumMap
은 기존 enum 클래스에 있는 enum type만을 키값으로 설정할 수 있기 때문에,
HashTable
보다 comapct 한 배열을 사용한다. 이것은 HashMap
보다 더 적은 메모리와 더 좋은 성능을 보여준다
결과의 차이를 확연하게 주기위해 hashMap의 initial size
를 100
으로 주었다. 물론 반복문의 개수와 같은 1000000로 주어도 load factor
가 0.75이기때문에 enumMap보다 조금 느리다 평균 3~4milliseconds
정도
테스트 코드
Map<String, Integer> hashMap = new HashMap<>(100, 0.75f);
Map<Plant.LifeCycle, Integer> enumMap = new EnumMap<>(Plant.LifeCycle.class);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
hashMap.put(String.valueOf(i), i);
}
long endTime = System.currentTimeMillis();
System.out.println("Elapsed time for HashMap: " + (endTime - startTime) + " milliseconds");
startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
enumMap.put(Plant.LifeCycle.values()[i % 3], i);
}
endTime = System.currentTimeMillis();
System.out.println("Elapsed time for enumMap: " + (endTime - startTime) + " milliseconds");
output
Elapsed time for HashMap: 22 milliseconds
Elapsed time for enumMap: 13 milliseconds
EnumMap
의 활용사례
public enum Phase{
SOLID, LIQUID, GAS;
public enum Transition {
MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),
BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID);
private final Phase from;
private final Phase to;
Transition(Phase from, Phase to) {
this.from = from;
this.to = to;
}
private static final Map<Phase, Map<Phase, Transition>>
m = Stream.of(values())
.collect(groupingBy(t -> t.from,
() -> new EnumMap<>(Phase.class),
toMap(t -> t.to, t -> t,
(x, y) -> y, () -> new EnumMap<Phase, Transition>(Phase.class)
)
));
public static Transition from(Phase from, Phase to) {
return m.get(from).get(to);
}
}
}