/////
Search
Duplicate
3️⃣

맵 처리

자바 8에서는 Map 인터페이스에 몇 가지 디폴트 메서드를 추가했다. 이는 기본적인 구현을 인터페이스에서 제공하는 기능 정도로 생각해두는 것이 편하다.
자주 사용되는 패턴을 개발자가 직접 구현할 필요가 없도록 구현을 추가한 것이다.

1. forEach 메서드

맵에서 키와 값을 반복하면서 확인하는 작업은 가장 잘 알려진 귀찮은 작업 중 하나다. Map.Entry<K, V>iterator를 사용하여 처리할 수 있다.
for (Iterator<Map.Entry<String, Integer>> iterator = humans.entrySet().iterator(); iterator.hasNext();) { Map.Entry<String, Integer> entry = iterator.next(); System.out.println(entry.getKey() + " " + entry.getValue()); }
Java
복사
자바 8에서부터 Map 인터페이스는 BiConsumer를 인수로 받는 forEach 메서드를 지원하므로 코드를 조금 더 간단하게 구현할 수 있다.
humans.forEach((friend, age) -> System.out.println(friend + " is " age + " years old");
Java
복사
forEach 디폴트 메서드의 구현은 다음과 같다.
default void forEach(BiConsumer<? super K, ? super V> action) { Objects.requireNonNull(action); for (Map.Entry<K, V> entry : entrySet()) { K k; V v; try { k = entry.getKey(); v = entry.getValue(); } catch (IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } action.accept(k, v); } }
Java
복사

2. 정렬 메서드

다음 두 개의 새로운 유틸리티를 이용하면 맵의 항목을 키 또는 값을 기준으로 정렬할 수 있다.
Entry.comparingByKey
Entry.comparingByValue
Map<String, Integer> humans = Map.ofEntries(Map.entry("A", 1), Map.entry("B", 2)); humans .entrySet() .stream() .sorted(Entry.comparingByKey()) .forEachOrdered(System.out::println);
Java
복사

3. getOrDefault 메서드

기존에는 찾으려는 키의 값이 존재하지 않는 경우, Null이 반환되므로 NullPointerException을 방지하려면 결과가 Null인지 확인해야 했었다.
자바 8에서는 이를 getOrDefault 메서드를 통해 해결할 수 있다.
이 메서드는 첫 번째 인수로 키를, 두 번째 인수로 기본값을 받으며 맵에 키가 존재하지 않는다면 두 번째로 인수로 받은 기본값을 리턴한다.
만약 키가 존재하고 값이 Null이라면 getOrDefaultNull을 반환한다. getOrDefault는 키가 존재하느냐의 여부에 따라서 두 번째 인수가 반환될지 말지를 결정한다는 것을 알아두자.

4. 계산 패턴

맵에 키가 존재하는지 여부에 따라 처리하고 결과를 저장해야 하는 상황이 필요한 경우가 있다.
예를 들어 키를 이용해 값비싼 동작을 실행해서 얻은 결과를 캐시하려 한다. 키가 존재하면 결과를 다시 계산할 필요가 없다. 다음의 세 가지 연산이 이런 상황에 도움을 줄 수 잇다.
computeIfAbsent
제공된 키에 해당하는 값이 없으면(값이 없거나 존재해도 Null인 경우) 키를 이용해 새 값을 계산하고 맵에 추가한다.
computeIfPresent
제공된 키가 존재한다면 새 값을 계산하고 맵에 추가한다.
compute
제공된 키로 새 값을 계산하고 맵에 저장한다.

5. 삭제 패턴

키를 인수로 받아 맵 항목을 제거하는 remove 메서드는 이미 알고 있다.
자바 8에서는 키가 특정한 값과 연관되었을 때만 항목을 제거하는 오버로드 버전 메서드를 제공한다.
humans.remove(key, value);
Java
복사

6. 교체 패턴

맵의 항목을 바꾸는 데 사용할 수 있는 두 개의 메서드가 추가되었다.
replaceAll
BiFunction을 적용한 결과로 각 항목의 값을 교체한다. 이 메서드는 앞서 살펴본 ListreplaceAll과 비슷한 동작을 수행한다.
replace → 책에선 대문자로 되어있는데, 라이브러리 가보니까 소문자인거 같아서 소문자로 썼다.
키가 존재하면 맵의 값을 바꾼다. 키가 특정 값으로 매핑되었을 때만 값을 교체하는 오버로드 버전도 있다.
Map<String, Integer> humans = new HashMap<>(); humans.put("A", 1); humans.put("B", 2); humans.replaceAll((name, age) -> name.toUpperCase());
Java
복사
불변 컬렉션이었다면 당연히 에러가 발생한다!

7. 합침

두 그룹의 연락처를 포함하는 두 개의 맵을 합친다고 가정하다. 다음처럼 putAll을 사용할 수 있다.
Map<String, Integer> firstHumans = Map.of("A", 1, "B", 1); Map<String, Integer> secondHumans = Map.of("C", 1, "D", 1); Map<String, Integer> allHumans = new HashMap<>(); allHumans.PutAll(firstHumans); allHumans.PutAll(secondHumans);
Java
복사
중복된 키가 존재하지 않는다면 위 연산을 잘 동작한다. 만약 중복된 키가 존재한다면?
merge 메서드를 이용해서 값을 좀 더 유연하게 병합할 수 있다.
Map<String, Integer> firstHumans = Map.of("A", 1, "B", 1); Map<String, Integer> secondHumans = Map.of("B", 1, "D", 1); Map<String, Integer> allHumans = new HashMap<>(); allHumans.PutAll(firstHumans); allHumans.forEach((name, age) -> allHumans.merge(name, age, (age1, age2) -> age1 + age2)); -> // 중복값일 경우, 나이를 더하는 전략
Java
복사