728x90
1. 올바르지 않은 방법 : ordinal()을 배열 인덱스로 사용
Set<Plant>[] plant ByLisfeCycle = (Set<Plant>[]) new Set[Plant.LifeCycle.values().length];
for(int i =0; i < plantsByLifeCycle.length; i++)
plantsByLifeCycle[i] = new HashSet<>();
for(Plant p : garden){
plantsByLifeCycle[p.lifeCycler.ordinal()].add(p);
}
for(int i =0; i<plantsByLifeCycle.length;i++)}{
System.out.println("%s: %s%n", Plant.LifeCycle.values()[i], plantsByLifeCycle[i]);
}
문제점
- 배열은 제네릭과 호환되지 않아 비검사 형변환을 수행해야한다. (컴파일이 깔끔하지 않다)
- 정수 값을 정확히 사용해야한다 : 잘못하면 ArrayIndexOutOfBoundException
2. EnumMap : 열거 타입을 키로 사용
Set<Plant>[] plantsByLifeCycleArr =
(Set<Plant>[]) new Set[Plant.LifeCycle.values().length];
for (int i = 0; i < plantsByLifeCycleArr.length; i++)
plantsByLifeCycleArr[i] = new HashSet<>();
for (Plant p : garden)
plantsByLifeCycleArr[p.lifeCycle.ordinal()].add(p);
// 결과 출력
for (int i = 0; i < plantsByLifeCycleArr.length; i++) {
System.out.printf("%s: %s%n",
Plant.LifeCycle.values()[i], plantsByLifeCycleArr[i]);
}
열거 타입을 키로 사용하도록 설계한 Map 구현체이다.
- 안전하지 않은 형변환 사용하지 않는다.
- 배열 인덱스 계산 과정 오류 가능성도 없다.
- 내부에서 배열을 사용해서 ordinal 배열만큼 성능이 나온다 : 낭비 되는 공간과 시간이 거의 없어 명확하고 안전하고 유지보수하기 좋다.
EnumMap의 생성자가 받는 키타입의 Class 객체는 한정적 타입 토큰으로 런타입 제네릭 타입정보를 제공한다.
3. EnumMap을 stream과 함께 사용할 때
스트림을 사용할 때 고유한 맵 구현체를 사용하기 때문에 EnumMap을 사용할 때 얻는 공간과 성능 이점이 사라진다는 문제가 있다.
System.out.println(Arrays.stream(garden)
.collect(groupingBy(p -> p.lifeCycle))); // 고유한 맵 구현체
System.out.println(Arrays.stream(garden)
.collect(groupingBy(p -> p.lifeCycle, // 원하는 맵 구현체 명시
() -> new EnumMap<>(LifeCycle.class), toSet())));
stream을 사용하면 enumMap 만 사용했을 때와 생성되는 맵의 개수가 다르다.
// 코드 37-2 EnumMap을 사용해 데이터와 열거 타입을 매핑한다.
System.out.println("using EnumMap");
Map<Plant.LifeCycle, Set<Plant>> plantsByLifeCycle =
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);
System.out.println("using stream");
// 코드 37-3 스트림을 사용한 코드 1 - EnumMap을 사용하지 않는다!
Map<LifeCycle, List<Plant>> collect = Arrays.stream(garden)
.collect(groupingBy(p -> p.lifeCycle));
System.out.println(collect);
System.out.println("using stream enumMap");
// 코드 37-4 스트림을 사용한 코드 2 - EnumMap을 이용해 데이터와 열거 타입을 매핑했다.
EnumMap<LifeCycle, Set<Plant>> collect1 = Arrays.stream(garden)
.collect(groupingBy(p -> p.lifeCycle,
() -> new EnumMap<>(LifeCycle.class), toSet()));
System.out.println(collect1);
EnumMap을 이용해 put한 코드드에서는 PERENNIAL이 없어도 생성된다. 반면 stream 을 이용한 코드에서는 2개만 생성된다.
'Dev Book Review > Effective Java' 카테고리의 다른 글
[Effective Java] item 39. 명명 패턴보다 애너테이션을 사용하라 (0) | 2020.06.27 |
---|---|
[Effective Java] item 38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라 (0) | 2020.06.27 |
[Effective Java] item 36. 비트 필드 대신 EnumSet을 사용하라 (0) | 2020.06.27 |
[Effective Java] item 35. ordinal 메서드 대신 인스턴스 필드를 사용하라 (0) | 2020.06.27 |
[Effective Java] item 34. int 상수 대신 열거 타입을 사용하라 (2) | 2020.06.27 |