작성 정보

- 작성일 : 2026-05-29

- 관련 문제 : PG42579 베스트 앨범

- 관련 문서 : 중첩 Map과 의미 있는 타입, Comparable과 compareTo

Map은 key로 값을 빠르게 찾기 위한 자료구조다. 그래서 일반적인 HashMap은 저장 순서나 정렬 순서를 보장하지 않는다. 정렬이 필요하면 entrySet, keySet, values 중 필요한 것을 꺼내서 정렬해야 한다.

Map 자체를 정렬하지 않는다

다음처럼 생각한다.

Map을 정렬한다 X
Map에서 Entry 목록을 꺼내 정렬한다 O

스트림으로 정렬할 수 있다.

genreMap.entrySet().stream()
        .sorted(Map.Entry.comparingByValue())
        .toList();

제출 환경이 Java 8 기준이라면 Collectors.toList()를 쓴다.

List<Map.Entry<String, Genre>> list = genreMap.entrySet().stream()
        .sorted(Map.Entry.comparingByValue())
        .collect(Collectors.toList());

또는 리스트로 만든 뒤 정렬해도 된다.

List<Map.Entry<String, Genre>> list = new ArrayList<>(genreMap.entrySet());
list.sort(Map.Entry.comparingByValue());

key 기준 정렬과 value 기준 정렬

key 기준 정렬은 다음처럼 쓴다.

list.sort(Map.Entry.comparingByKey());

value 기준 정렬은 다음처럼 쓴다.

list.sort(Map.Entry.comparingByValue());

value가 직접 비교 가능한 타입이어야 한다. Integer, String은 이미 가능하다. 직접 만든 클래스라면 Comparable을 구현하거나 별도 Comparator를 넘긴다.

list.sort(Map.Entry.comparingByValue(
        Comparator.comparingInt(Genre::getTotalPlayCounts).reversed()
));

코딩테스트에서는 getter를 만들지 않았다면 람다로 직접 비교해도 된다.

list.sort((a, b) ->
        Integer.compare(b.getValue().totalPlayCounts, a.getValue().totalPlayCounts)
);

computeIfAbsent

computeIfAbsent는 key가 없을 때만 값을 만들어 넣고, 최종 value를 반환한다.

genreMap.computeIfAbsent(genres[i], Genre::new)
        .addSong(song);

직접 풀어 쓰면 다음과 같다.

if (!genreMap.containsKey(genres[i])) {
    genreMap.put(genres[i], new Genre(genres[i]));
}
genreMap.get(genres[i]).addSong(song);

Genre::new는 key를 인자로 받아 새 값을 만드는 함수다.

Function<String, Genre> f = Genre::new;

그래서 computeIfAbsent는 함수형 인터페이스를 사용하는 API라고 볼 수 있다. 다만 Map의 상태를 변경하므로 순수 함수형 코드라고 보기는 어렵다.

언제 쓰면 좋은가

computeIfAbsent는 "없으면 만들고, 있으면 기존 것을 사용한다"는 패턴에 좋다.

Map<String, List<Integer>> map = new HashMap<>();

map.computeIfAbsent("a", key -> new ArrayList<>())
        .add(1);

다음처럼 그룹핑할 때 자주 나온다.

Map<String, List<Song>> songsByGenre = new HashMap<>();

for (Song song : songs) {
    songsByGenre.computeIfAbsent(song.genre, key -> new ArrayList<>())
            .add(song);
}

실수 체크

  • HashMap 자체의 순서를 믿지 않았는가
  • 정렬이 필요하면 entrySet()을 꺼냈는가
  • value 기준 정렬이면 value가 비교 가능한 타입인가
  • key가 없을 때만 새 객체를 만들고 싶은 상황인가
  • computeIfAbsent의 두 번째 인자가 key를 받아 value를 만드는 함수라는 점을 이해했는가