변수의 기록

Java Map 컬렉션 정리 – HashMap, LinkedHashMap, TreeMap 본문

자바/자바

Java Map 컬렉션 정리 – HashMap, LinkedHashMap, TreeMap

불광동 물주먹 2025. 4. 21. 16:54

 

먼저 이 글을 쓰게 된 시작 점은 treeMap을 굳이 왜 써야할까? 어떤 상황에서 사용하면 이점이 클까? 

그리고 어떤 구조로 관리가 될까? 
DB에서 원하는 정렬된 값을 받아와 hashmap에 담으면 되는데? 라는 아주 얇팍한 지식으로 시작됐다....

정리 시작해 보겠습니다.

 

Java Map 컬렉션 정리 – HashMap, LinkedHashMap, TreeMap


1. Map 컬렉션이란?

Map은 키(key)와 값(value)의 쌍으로 데이터를 저장하는 자료구조다.
중복된 키는 허용하지 않으며, 각 키는 하나의 값만 가질 수 있다.

Java에서 대표적인 Map 구현체는 아래 3가지다.

  • HashMap: 기본 해시 기반 Map
  • LinkedHashMap: 순서 보장 + 해시 기반 Map
  • TreeMap: 정렬 기반 Map

2. Map 계열 자료구조 비교


 

항목 HashMap LinkedHashMap TreeMap
내부 구조 해시 테이블 (배열 + 체이닝) 해시 테이블 + 이중 연결 리스트 Red-Black Tree (이진 탐색 트리)
순서 보장 없음 입력 순서 또는 접근 순서 유지 Key 정렬 순서 유지
키 정렬 여부 없음 없음 오름차순 정렬 (Comparator 지정 가능)
접근/삽입 시간복잡도 평균 O(1), 최악 O(log n) 평균 O(1) (추가 포인터 연산 있음) O(log n)
메모리 사용량 적음 중간 (포인터 추가) 많음 (트리 포인터 구조)
용도 빠른 조회 중심 순서 + 조회 정렬 + 범위 검색

3. 각 Map의 구조적 차이

3.1 HashMap

  • 기본적으로 Node<K,V>[] 배열을 해시 버킷으로 사용
  • 키를 hash()로 계산해 배열의 인덱스를 결정하고, 충돌이 발생하면 체이닝 구조 (next) 로 연결
  • Java 8 이상에서는 충돌이 많아지면 TreeNode (Red-Black Tree) 로 자동 전환
    (버킷 내 요소가 8개 이상, 전체 버킷 수 64 이상 조건)
 
static class Node<K,V> { final int hash; final K key; V value; Node<K,V> next; }
  • 빠른 조회가 목적일 때 사용
  • 순서 보장이 필요 없을 때 적합

3.2 LinkedHashMap

  • HashMap을 상속해서 구현됨
  • 각 Entry에 before, after 포인터를 추가해 입력 순서 또는 접근 순서 유지
  • 해시 저장 구조는 그대로 사용하면서, 전체 엔트리를 이중 연결 리스트로 연결
 
static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> { LinkedHashMapEntry<K,V> before, after; }
  • put() 시 포인터로 순서 연결
  • 순회 시에는 before → after 방향으로 순서 보장됨

3.3 TreeMap

  • 내부적으로 Red-Black Tree (이진 탐색 트리) 구조로 key를 저장
  • key끼리 Comparable을 구현하거나 Comparator를 전달해야 정렬 가능
  • key 값이 들어올 때마다 정렬된 위치에 자동 삽입됨
 
static final class Entry<K,V> { K key; V value; Entry<K,V> left, right, parent; boolean color; }
  • key 기준 정렬이 필요한 경우에 사용
  • 범위 기반 탐색 (subMap, tailMap, headMap)에 매우 유용

4. TreeMap의 key 제한?

TreeMap의 key는 정수가 아니어도 된다.
중요한 것은 비교 가능성(Comparable 또는 Comparator) 이다.

사용 가능한 예:

  • Integer, String, LocalDate, BigDecimal 등 Comparable 구현체
  • 사용자 정의 클래스 + Comparator 전달
 
TreeMap<String, String> map = new TreeMap<>(); map.put("brc_info", "정보");

5. TreeMap vs ArrayList


 

항목 TreeMap ArrayList
내부 구조 Red-Black Tree (이진 트리) Object[] (배열)
순서 기준 key 정렬 기준 삽입 순서 (인덱스 순)
접근 속도 O(log n) O(1) (인덱스 기반)
삽입/삭제 위치 제어 정렬 기준에 따라 자동 결정 위치 직접 지정 가능
용도 정렬된 Map이 필요할 때 순차 데이터, 반복 처리

→ TreeMap은 구조상 연속된 메모리는 아니지만,
정렬 순서를 논리적으로 항상 유지하는 자료구조임.


6. 실무에서 TreeMap/TreeSet이 필요한 경우

TreeMap

  • 날짜별 데이터 조회 캐시 (예: 날짜별 매출)
  • 등급 기준 혜택 구성 (TreeMap<Integer, String>)
  • 실시간 정렬이 필요한 데이터 수집기 (ex. 실시간 로그 분류)

TreeSet

  • 중복 제거 + 자동 정렬된 집합 필요
  • 실시간 랭킹 처리 (점수 기준 자동 정렬)
  • 알파벳순 이름 목록 등 정렬된 리스트

7. 정렬은 화면에서 할까, 서버에서 할까?

  • 소규모 데이터 → 프론트(JS)에서 정렬 (array.sort())
  • 대규모 데이터 or 페이징 → 백엔드에서 DB 정렬 (ORDER BY)
  • 범위 검색/정렬 상태 유지가 중요 → 서버 메모리 내에서 TreeMap 또는 정렬된 리스트로 캐싱
 
users.sort((a, b) -> a.name.compareTo(b.name)); // JS 정렬 SELECT * FROM user ORDER BY age ASC LIMIT 50; // SQL 정렬 TreeMap<LocalDate, Integer> sales = new TreeMap<>(); // 서버 메모리 정렬

8. 언제 어떤 Map을 써야 할까?

 

조건 추천 Map  이유
빠른 조회 (순서 무관) HashMap 평균 O(1)
입력 순서 기억해야 함 LinkedHashMap 연결 포인터로 순서 보존
정렬된 key로 순회/탐색 필요 TreeMap 정렬 자동 유지, 범위 검색 용이
key 중복 없이 정렬만 필요 TreeSet Set 특성 + 정렬

마무리

정렬이 필요한 경우, 단순히 ORDER BY로 해결할 수 있지만
정렬 상태를 메모리 내에서 유지하거나, 범위 탐색이 자주 발생한다면
TreeMap 또는 TreeSet은 매우 유용한 선택이다.

반면, 빠른 접근만 필요하고 정렬이 불필요하다면 HashMap이 여전히 가장 강력한 기본 선택이다.