[Java] EnumMap이란?
0. 들어가기 전에
체스 미션을 진행하면서, HashMap을 EnumMap으로 리팩토링을 해봤습니다. 처음 쓰는거라 어떤 역할을 하는지 몰라 정리해 봅니다.
1. EnumMap 이란?
Enum 타입의 Key를 갖는 특화된 맵
EnumMap은 하나의 Enum을 Key로 갖는다. 또한 HashMap과는 달리 HashMap을 사용하지 않고 Array로 구현이 되어서 효율적이다.
2. EnumMap의 특징
2.1 속도
public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
implements java.io.Serializable, Cloneable
{
private final Class<K> keyType;
private transient K[] keyUniverse;
private transient Object[] vals;
//...
public EnumMap(Class<K> keyType) {
this.keyType = keyType;
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
}
}
EnumMap의 내부 구현을 보면 K[]
로 구성되어 있다.
HashMap은 어떠한 방식보다 검색 방법이 빠르지만, 내부적으로 해싱 알고리즘을 사용하기 때문에 저장할 때 느릴 수 밖에 없다. 하지만 EnumMap은 배열을 사용하고 Key에 하나의 Enum 타입만 들어가는게 보장되기 때문에 속도가 빠르다.
[EnumMap과 HashMap 속도 비교]
@Test
void EnumMap과_HashMap_속도를_비교한다() {
// given
StopWatch enumStopWatch = new StopWatch();
StopWatch hashStopWatch = new StopWatch();
final Map<ChessType, Integer> enumMap = new EnumMap<>(ChessType.class);
final Map<ChessType, Integer> hashMap = new HashMap<>();
// when
enumStopWatch.start();
for (int i = 0; i < 10_000_000; i++) {
for (ChessType type : ChessType.values()) {
enumMap.put(type, i);
}
}
enumStopWatch.stop();
hashStopWatch.start();
for (int i = 0; i < 10_000_000; i++) {
for (ChessType type : ChessType.values()) {
hashMap.put(type, i);
}
}
hashStopWatch.stop();
// then
log.info("EnumMap Total Put Time : {}", enumStopWatch.getTotalTimeMillis());
log.info("HashMap Total Put Time : {}", hashStopWatch.getTotalTimeMillis());
}
ChessType은 총 6개 이고 천만번 반복해서 60,000,000번 반복해서 데이터를 넣었다.
시간 차이는 아래와 같이 나온다.
test.enummap.EnumMapTest - EnumMap Total Put Time : 396
test.enummap.EnumMapTest - HashMap Total Put Time : 762
데이터가 더 커지면 속도 차이는 유의미할 정도로 차이가 날 것 같다.
2.2 Enum 순서 보장
public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
implements java.io.Serializable, Cloneable
{
public V put(K key, V value) {
typeCheck(key);
int index = key.ordinal();
Object oldValue = vals[index];
vals[index] = maskNull(value);
if (oldValue == null)
size++;
return unmaskNull(oldValue);
}
}
EnumMap의 put 메서드는 key이 순서를 인덱스로 사용한다. 따라서 LinkedHashMap처럼 순서가 보장된다. 실제로 출력을 해보면 Key의 순서가 차례대로 나오며, Enum의 순서가 바뀌면 바껴서 출력이 된다.
순서를 다르게 하고 싶으면 stream을 사용해 정렬해야한다.
2.3 Null key가 안 됨
Runtime시 에 null을 key로 넣을려면 NPE가 발생한다. 반면에 HashMap은 key로 null이 push가 된다.
2.4 Thread Unsafe
EnumMap은 Thread safe하지 않기 때문에 안전하게 만들려면 Collections.synchronizedMap()
을 사용해야한다.
Map<EnumKey, V> enumMap = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));
※ 참고
'LANGUAGE > [JAVA]' 카테고리의 다른 글
[Java] LinkedHashMap의 방어적 복사 (0) | 2023.03.13 |
---|---|
[Java] JVM - Garbage Collector (2) | 2023.03.12 |
[Java] JVM - 메모리 구조 (4) | 2023.02.28 |
[Java] 롬복의 원리 (0) | 2022.06.08 |
[JAVA] JVM (0) | 2022.06.04 |