개요
Guava 라이브러리에서 가장 자주 쓰이는 MultiMap과 BiMap 에 대해 알아본다.
MultiMap
key 하나에 여러 value 를 매핑하려고 할 때 쓰이는 인터페이스다.
Java 에서 제공하는 기본 Map<K,V> 의 Value 타입을 리스트로 직접 선언하여 다룰 수 있지만 단점이 있다.
- 문법이 장황해진다.
- 같은 key 에 값을 쓰면, 마지막 value 로 덮어써진다.
class ListMap {
@DisplayName("prolix list map")
@Test
void prolixListMapTest() {
// given
Map<String, List<String>> map = new HashMap<>();
// 매번 값을 쓸 때마다 List 객체 생성을 명시해야 한다.
map.put("Fruit", List.of("Banana"));
// 가장 마지막에 put 된 값으로 overwrite
map.put("Fruit", List.of("Apple"));
// then
assertThat(map.get("Fruit"))
.hasSize(1)
.isEqualTo(List.of("Apple"));
}
}
ArrayListMutliMap
언제 쓰나?
value 에 unique 함을 보장할 필요가 없을 때 사용한다.
value 는 ArrayList 타입으로 uniqueness 를 보장하지 않는다.
class ArrayListMultiMapTest {
@DisplayName("duplicates is allowed in a ArrayListMultiMap")
@Test
void multipleValuesTest() {
// given
Multimap<String, String> multiMap = ArrayListMultimap.create();
// when
multiMap.put("Fruit", "Apple");
multiMap.put("Fruit", "Banana");
multiMap.put("Fruit", "Banana");
multiMap.put("Fruit", "Cherry");
multiMap.put("Vegetable", "Carrot");
// then
assertAll(
() -> assertThat(multiMap.keySet()).hasSize(2),
() -> assertThat(multiMap.get("Fruit"))
.hasSize(4)
.containsAll(List.of("Apple", "Banana", "Banana", "Cherry"))
);
}
}
MultiMap 으로 다음 장점을 얻는다.
- 문법이 간결해진다.
명시적으로 값을 쓸 때마다 List 객체를 생성할 필요가 없다.
같은 key 에 여러 value 를 간단하게 담을 수 있다.
HashMultiMap
언제 쓰나?
value 가 unique 함을 보장해야 할 때 사용한다.
value 는 Set 타입으로 uniqueness 를 보장한다.
class HashMultimapTest {
@DisplayName("HashMultimap guarantees that the value is unique")
@Test
void duplicateTest() {
// given
Multimap<String, Long> multiMap = HashMultimap.create();
// when
multiMap.put("prices", 100L);
multiMap.put("prices", 100L);
multiMap.put("prices", 100L);
// then
assertThat(multiMap.get("prices"))
.hasSize(1)
.isEqualTo(Set.of(100L));
}
}
두 구현체 모두다 thread-safe 하지 않다.
BiMap
언제 쓰나?
Map의 <K, V> 는 K 만 가지고 값을 조회할 수 있다.
역방향인 V -> K 로 조회하는 API 를 제공한다.
public class BiMapTest {
@DisplayName("BiMap allows getting the value inversely")
@Test
void getValueInverse() {
// given
BiMap<String, Integer> asciiBiMap = HashBiMap.create(5);
asciiBiMap.put("A", 65);
asciiBiMap.put("B", 66);
asciiBiMap.put("C", 67);
BiMap<Integer, String> inversedBiMap = asciiBiMap.inverse();
// when then
assertAll(
() -> assertThat(inversedBiMap.get(65)).isEqualTo("A"),
() -> assertThat(inversedBiMap.get(66)).isEqualTo("B"),
() -> assertThat(inversedBiMap.get(67)).isEqualTo("C")
);
}
}
BiMap 은 `inverse()` 메소드로 역방향 Map 생성을 지원하는 자료구조기 때문에
Value 중복을 허용하지 않는다.
@DisplayName("BiMap does not allow writing the duplicates because it can't be inverted when duplicates exists")
@Test
void duplicatesNotAllowedTest() {
// given
BiMap<String, Integer> asciiBiMap = HashBiMap.create(2);
asciiBiMap.put("A", 65);
assertThatThrownBy(
// invert 하는 순간 65 -> A, B 가 되므로 중복 발생.
// 허용되지 않는다.
()-> asciiBiMap.put("B", 65)
).isInstanceOf(IllegalArgumentException.class)
.hasMessage("value already present: 65");
}
'JVM > Java' 카테고리의 다른 글
[Java] 예외 번역과 예외 연쇄 기법 (0) | 2024.09.30 |
---|---|
[Java] Thread 상속 대신 Runnable 을 사용하라. (0) | 2024.07.21 |
[Java] Generic vs WildCard (2) | 2024.01.07 |
[객체지향] 잘못된 DRY 원칙 적용 (0) | 2023.12.16 |
[Java] Enum 에는 equals 대신 == 을 써라 (0) | 2023.11.22 |