F-LAB JAVA · 3주차 · Phase 2 · 컬렉션 프레임워크 전체 지도
🏆 Phase 2 완주 — 자바 컬렉션 마스터 달성
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
자바 컬렉션 = 4가지 자료구조 (List/Set/Queue/Map) × 다양한 구현체 (트레이드오프 선택).
각 인터페이스는 의미 를 정의하고, 각 구현체는 메모리/시간 트레이드오프 를 제공한다.
Phase 2 를 마스터하며 시나리오 → 자료구조 → 구현체 의 결정 능력을 얻었다.
이 한 Unit 에서 Unit 2.1 ~ 2.5 모든 학습이 응집 되고, 3주차의 컬렉션 학습이 졸업 한다.
| 시스템 | 비유 |
|---|---|
| List 4형제 | 카탈로그 진열대 (순서 있음) |
| Set 3형제 | 단일 컬렉션 (중복 X) |
| Queue 5형제 | 대기 줄 (FIFO) |
| Map 5형제 | 라벨 서랍 (키-값) |
| 17개 구현체 | 각자 다른 용도와 장단점 |
→ 컬렉션 마스터의 능력 = 정확한 도구 선택.
1. Phase 2 학습 여정 회고
2. 자바 컬렉션 전체 지도 (한눈에)
3. 4가지 자료구조 의미적 차이
4. 시간 복잡도 종합 표
5. 시나리오별 의사결정 트리
6. ILIC 의 90:9:1 법칙 완성
7. Legacy 컬렉션 (절대 안 씀)
8. Phase 2 졸업 시험 — 30문항
9. Phase 3 진입 + 능력 점검
Iterable<E> (java.lang)
│
▼
Collection<E> (java.util)
│
├── List<E>
│ ArrayList, LinkedList, Vector(Legacy),
│ CopyOnWriteArrayList, List.of (불변)
│
├── Set<E>
│ │ HashSet, LinkedHashSet, TreeSet,
│ │ EnumSet, CopyOnWriteArraySet,
│ │ ConcurrentHashMap.newKeySet()
│ │
│ └── SortedSet<E>
│ └── NavigableSet<E>
│ TreeSet
│
└── Queue<E>
│ LinkedList, PriorityQueue,
│ ConcurrentLinkedQueue
│
├── Deque<E>
│ ArrayDeque, LinkedList,
│ ConcurrentLinkedDeque
│
└── BlockingQueue<E>
ArrayBlockingQueue, LinkedBlockingQueue,
PriorityBlockingQueue, DelayQueue,
SynchronousQueue
Map<K, V> (별도 계층)
│ HashMap, LinkedHashMap, Hashtable(Legacy),
│ EnumMap, WeakHashMap, IdentityHashMap,
│ Properties(Legacy 자식)
│
├── SortedMap<K, V>
│ └── NavigableMap<K, V>
│ TreeMap, ConcurrentSkipListMap
│
└── ConcurrentMap<K, V>
ConcurrentHashMap, ConcurrentSkipListMap
Map 의 view (Collection 인터페이스 활용):
- keySet() → Set<K>
- values() → Collection<V>
- entrySet() → Set<Map.Entry<K, V>>
인터페이스: List<E>
구현체:
1. ArrayList — 배열 기반, 90% 정답
2. LinkedList — 이중 연결, Deque 도 구현
3. Vector — Java 1.0 Legacy
4. CopyOnWriteArrayList — 읽기 위주 멀티스레드
특수:
5. List.of (Java 9+) — 불변 List
6. Collections.synchronizedList — 동기화 wrapper
인터페이스: Set<E>
구현체:
1. HashSet — 해시 테이블 (90% 정답)
2. LinkedHashSet — HashSet + 순서
3. TreeSet — Red-Black Tree, 정렬
4. EnumSet — Enum 전용, 비트벡터
5. CopyOnWriteArraySet — 멀티스레드 (배열 기반)
6. ConcurrentHashMap.newKeySet() — 멀티스레드
특수:
7. Set.of (Java 9+) — 불변 Set
인터페이스: Queue<E>, Deque<E>, BlockingQueue<E>
일반 Queue:
1. ArrayDeque — 원형 배열 (90% 정답)
2. LinkedList — 비권장
3. PriorityQueue — Binary Heap
멀티스레드 (락-프리):
4. ConcurrentLinkedQueue
5. ConcurrentLinkedDeque
멀티스레드 (BlockingQueue):
6. ArrayBlockingQueue
7. LinkedBlockingQueue
8. PriorityBlockingQueue
9. DelayQueue
10. SynchronousQueue
인터페이스: Map<K, V>
구현체:
1. HashMap — 해시 테이블 (90% 정답)
2. LinkedHashMap — HashMap + 순서/LRU
3. TreeMap — Red-Black Tree
4. Hashtable — Java 1.0 Legacy
5. ConcurrentHashMap — 멀티스레드 표준
6. ConcurrentSkipListMap — 멀티스레드 + 정렬
7. EnumMap — Enum 키, 비트벡터
8. WeakHashMap — GC 시 자동 제거
9. IdentityHashMap — 참조 동일성
특수:
10. Map.of (Java 9+) — 불변 Map
11. Properties — Hashtable 의 자식 (legacy)
12. Collections.synchronizedMap — 동기화 wrapper
만난 컬렉션:
- 인터페이스: ~ 10개
- 일반 구현체: ~ 25개
- 특수 (불변, wrapper): ~ 7개
총 30여 가지
→ Phase 2 가 자바 컬렉션의 거의 모든 풍경.
자바 컬렉션의 최상위 인터페이스 2가지는?
답:
1. Iterable<E> (java.lang)
Map<K, V> (java.util)→ "Iterable + Map" 이 자바 컬렉션의 두 축.
| 자료구조 | 핵심 의미 | 순서 | 중복 | 인덱스 | 키-값 |
|---|---|---|---|---|---|
| List | "순서 있는 가변 시퀀스" | ✓ 삽입 순서 | ✓ | ✓ | ❌ |
| Set | "중복 없는 모음" | △ 구현체별 | ❌ | ❌ | ❌ |
| Queue | "처리 대기 줄" | ✓ FIFO | ✓ | ❌ | ❌ |
| Map | "키-값 매핑" | △ 구현체별 | 키 ❌, 값 ✓ | 키 | ✓ |
시나리오 → 자료구조 결정:
자료구조 선택 5단계:
Step 1: 키-값 매핑인가?
YES → Map
NO → Step 2
Step 2: 중복을 허용하는가?
NO → Set
YES → Step 3
Step 3: FIFO 처리인가?
YES → Queue
NO → Step 4
Step 4: 인덱스 접근 필요한가?
YES → List
NO → Step 4 답: List (대부분)
Step 5: 추가 요구사항?
- 정렬 필요? → Tree 계열
- 순서 유지? → Linked 계열
- 멀티스레드? → Concurrent 계열
- Enum 키? → EnumSet/EnumMap
- 불변? → of() 사용
"순서 있는 가변 시퀀스" — ILIC 에서:
✓ DB 조회 결과 (JPA 가 ArrayList 반환)
✓ 도메인 객체의 컬렉션 필드 (Shipment 의 List<Cargo>)
✓ DTO 변환 결과
✓ 처리 순서가 있는 작업 단계
✓ 페이지네이션 결과
"중복 없는 모음" — ILIC 에서:
✓ 권한 집합 (Set<Permission>)
✓ 처리된 ID 추적 (Set<Long> processedIds)
✓ 중복 제거된 노선 목록
✓ Enum 집합 (EnumSet)
✓ 이벤트 리스너 등록 (CopyOnWriteArraySet)
"처리 대기 줄" — ILIC 에서:
✓ 이벤트 큐 (비동기 처리)
✓ 작업 큐 (워커 스레드 풀)
✓ 알림 발송 큐
✓ 메시지 큐 클라이언트 (Kafka 내부)
✓ BFS 그래프 탐색 (경로 계산)
"키-값 매핑" — ILIC 에서:
✓ 캐시 (Map<Long, Shipment>)
✓ 인덱싱 (List → Map 변환)
✓ 그룹핑 결과 (groupingBy)
✓ 카운팅 (counting)
✓ 설정값 매핑
✓ JSON 응답 (LinkedHashMap)
✓ 시간순 이벤트 (TreeMap)
Map 과 List 의 결정적 차이를 한 문장으로?
답:
선택:
| 작업 | ArrayList | LinkedList | Vector | CopyOnWriteArrayList |
|---|---|---|---|---|
get(i) | O(1) | O(n) | O(1) | O(1) |
add(e) 끝 | O(1) amortized | O(1) | O(1) synchronized | O(n) 복사 |
add(0, e) 앞 | O(n) | O(1) | O(n) | O(n) |
add(i, e) 중간 | O(n) | O(n) | O(n) | O(n) |
remove(끝) | O(1) | O(1) | O(1) | O(n) |
remove(0) | O(n) | O(1) | O(n) | O(n) |
contains | O(n) | O(n) | O(n) | O(n) |
size | O(1) | O(1) | O(1) | O(1) |
| 멀티스레드 | unsafe | unsafe | safe | safe (락-프리 읽기) |
| 작업 | HashSet | TreeSet | LinkedHashSet | EnumSet |
|---|---|---|---|---|
add(e) | O(1) 평균 | O(log n) | O(1) 평균 | O(1) |
contains(e) | O(1) 평균 | O(log n) | O(1) 평균 | O(1) |
remove(e) | O(1) 평균 | O(log n) | O(1) 평균 | O(1) |
iterator | O(capacity) | O(log n) | O(1) | O(1) |
| 순회 | O(n + capacity) | O(n) | O(n) | O(n) |
first/last | (없음) | O(log n) | (없음) | (없음) |
| 작업 | ArrayDeque | LinkedList | PriorityQueue | BlockingQueue |
|---|---|---|---|---|
offer(e) | O(1) | O(1) | O(log n) | O(1) ~ O(log n) |
poll() | O(1) | O(1) | O(log n) | O(1) ~ O(log n) |
peek() | O(1) | O(1) | O(1) | O(1) |
contains | O(n) | O(n) | O(n) | O(n) |
put (차단) | — | — | — | O(1) ~ blocking |
take (차단) | — | — | — | O(1) ~ blocking |
| 작업 | HashMap | LinkedHashMap | TreeMap | Hashtable | ConcurrentHashMap |
|---|---|---|---|---|---|
put | O(1) 평균 | O(1) 평균 | O(log n) | O(1) syn. | O(1) 평균 |
get | O(1) 평균 | O(1) 평균 | O(log n) | O(1) syn. | O(1) 평균 |
remove | O(1) 평균 | O(1) 평균 | O(log n) | O(1) syn. | O(1) 평균 |
containsKey | O(1) 평균 | O(1) 평균 | O(log n) | O(1) syn. | O(1) 평균 |
containsValue | O(n) | O(n) | O(n) | O(n) | O(n) |
firstKey/lastKey | (없음) | (없음) | O(log n) | (없음) | (없음) |
size | O(1) | O(1) | O(1) | O(1) | O(1) 근사 |
| 멀티스레드 | unsafe | unsafe | unsafe | safe | safe (lock-stripe) |
Java 8+ 의 트리 변환:
HashSet, HashMap:
- 평균: O(1)
- 최악 (모든 키 같은 버킷): O(log n) (Java 8+ 트리)
- Java 7 까지는 O(n) (연결 리스트만)
ConcurrentHashMap 도 동일
암기:
자료구조 → 평균 → 최악:
HashSet, HashMap:
→ O(1) → O(log n)
TreeSet, TreeMap:
→ O(log n) → O(log n)
LinkedList:
→ O(1) 양 끝, O(n) 중간
ArrayList:
→ O(1) 인덱스, O(n) 중간
ArrayDeque (Queue):
→ O(1) 양 끝
PriorityQueue:
→ O(log n) 삽입/추출, O(1) peek
ArrayList 의
add(e)가 O(1) amortized 인 이유와 LinkedList 의add(e)가 O(1) 인 이유의 차이는?
답:
ArrayList:
LinkedList:
→ 미묘한 차이지만 의미 다름.
시나리오 → 자료구조 → 구현체:
[Step 1: 자료구조 결정]
키로 값 찾는가?
├── YES → Map (Step 2-M)
└── NO → 다음
중복 허용?
├── NO → Set (Step 2-S)
└── YES → 다음
FIFO 처리?
├── YES → Queue (Step 2-Q)
└── NO → List (Step 2-L)
[Step 2-M: Map 구현체 결정]
추가 요구사항:
├── 정렬 키 → TreeMap
├── 순서/LRU → LinkedHashMap
├── 멀티스레드 → ConcurrentHashMap
├── Enum 키 → EnumMap
├── 불변 → Map.of
└── 그 외 → HashMap (90%)
[Step 2-S: Set 구현체 결정]
추가 요구사항:
├── 정렬 → TreeSet
├── 순서 → LinkedHashSet
├── 멀티스레드 → ConcurrentHashMap.newKeySet()
├── Enum → EnumSet
├── 불변 → Set.of
└── 그 외 → HashSet (90%)
[Step 2-Q: Queue 구현체 결정]
멀티스레드?
├── NO → Step 3-Q-single
└── YES → Step 3-Q-multi
Step 3-Q-single:
├── 우선순위 → PriorityQueue
├── Stack 도 → ArrayDeque (push/pop)
└── 일반 → ArrayDeque
Step 3-Q-multi:
├── 차단 필요 → LinkedBlockingQueue (또는 ArrayBlockingQueue)
├── 우선순위 + 차단 → PriorityBlockingQueue
├── 지연 → DelayQueue
├── 핸드오프 → SynchronousQueue
└── 락-프리 → ConcurrentLinkedQueue
[Step 2-L: List 구현체 결정]
추가 요구사항:
├── 멀티스레드 읽기 위주 → CopyOnWriteArrayList
├── 멀티스레드 균형 → synchronizedList
├── 불변 → List.of
└── 그 외 → ArrayList (90%)
요구사항: ID 로 빠른 조회, 멀티스레드 환경
결정:
1. 키로 찾기 → Map ✓
2. 추가 요구: 멀티스레드 → ConcurrentHashMap
코드:
private final ConcurrentMap<Long, Shipment> cache = new ConcurrentHashMap<>();
요구사항: 최대 10개, 접근 시 끝으로 이동, 빠른 검색
결정:
1. 키로 찾기 → Map ✓
2. 추가 요구: 순서 + LRU → LinkedHashMap(accessOrder=true)
코드:
private final Map<Long, Shipment> recent = new LinkedHashMap<>(16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Long, Shipment> eldest) {
return size() > 10;
}
};
요구사항: 이벤트를 큐에 넣고 워커가 처리, 멀티스레드
결정:
1. FIFO → Queue ✓
2. 추가 요구: 멀티스레드 + 차단 → LinkedBlockingQueue
코드:
private final BlockingQueue<ShipmentEvent> queue = new LinkedBlockingQueue<>(1000);
요구사항: 권한 집합, 빠른 contains, 멀티스레드 없음
결정:
1. 중복 X → Set ✓
2. 추가 요구: Enum 타입 → EnumSet
코드:
Set<Permission> permissions = EnumSet.of(Permission.READ, Permission.WRITE);
요구사항: 시간 순서로 정렬, 범위 검색
결정:
1. 키 (시간) 로 찾기 → Map ✓
2. 추가 요구: 정렬 + 범위 → TreeMap
코드:
TreeMap<LocalDateTime, Event> timeline = new TreeMap<>();
timeline.subMap(from, to);
요구사항: JPA 가 반환, 순서 있는 시퀀스
결정:
1. 키-값 X → 다음
2. 중복 허용 → List ✓
3. 추가 요구 없음 → ArrayList
코드:
List<Shipment> shipments = repository.findAll(); // JPA 가 ArrayList 반환
요구사항: 리스너 등록/제거, 멀티스레드 읽기 위주
결정:
1. 키-값 X → 다음
2. 중복 X → Set ✓
3. 추가 요구: 멀티스레드 + 읽기 위주 → CopyOnWriteArraySet
코드:
Set<EventListener> listeners = new CopyOnWriteArraySet<>();
"운송장 ID 로 시간 순으로 정렬된 캐시" 를 만들려면?
답:
// 단일 스레드
TreeMap<Long, Shipment> cache = new TreeMap<>();
// 멀티스레드
ConcurrentSkipListMap<Long, Shipment> cache = new ConcurrentSkipListMap<>();
ILIC 코드에서 컬렉션 사용 비율:
[90% — 핵심 4 가지]
ArrayList<E>
- DB 결과
- 도메인 컬렉션
- DTO 변환
- 일반 List
HashMap<K, V>
- 캐시 (단일 스레드)
- 인덱싱
- 그룹핑
- 빈도 카운트
HashSet<E>
- 권한 집합
- 처리된 ID 추적
- 중복 제거
ConcurrentHashMap<K, V>
- 캐시 (멀티스레드)
- 빈도 카운터 (+ AtomicLong)
[9% — 특수 케이스]
LinkedHashMap (LRU 캐시, 응답 JSON 순서)
TreeMap (시간순 이벤트, 범위 검색)
EnumMap / EnumSet (Enum 키/값)
ArrayDeque (Queue, Stack)
PriorityQueue (우선순위)
LinkedBlockingQueue (작업 큐, 멀티스레드)
ConcurrentLinkedQueue (락-프리 멀티스레드 Queue)
CopyOnWriteArraySet/List (Listener 패턴)
List.of, Map.of, Set.of (불변 상수)
[1% — 드문 사용]
WeakHashMap (자동 GC 캐시)
IdentityHashMap (참조 동일성)
ConcurrentSkipListMap (멀티스레드 정렬)
DelayQueue (스케줄링)
SynchronousQueue (핸드오프)
LinkedList (드물게)
[0% — 절대 사용 X (Legacy)]
Vector
Hashtable
Stack 클래스
Properties (예외: Spring 설정)
// 매일 작성하는 코드의 90%:
// 1. 캐시 패턴
private final ConcurrentMap<Long, Shipment> cache = new ConcurrentHashMap<>();
public Shipment get(Long id) {
return cache.computeIfAbsent(id, this::load);
}
// 2. DB 조회
List<Shipment> shipments = repository.findByStatus(status);
// 3. Stream 변환
List<ShipmentResponse> responses = shipments.stream()
.map(ShipmentResponse::from)
.toList();
// 4. 그룹핑
Map<String, List<Shipment>> byRoute = shipments.stream()
.collect(Collectors.groupingBy(Shipment::getRoute));
// 5. 중복 제거
Set<String> uniqueBlNos = shipments.stream()
.map(Shipment::getBlNo)
.collect(Collectors.toSet());
// 6. 빈도 카운트
Map<String, Long> counts = shipments.stream()
.collect(Collectors.groupingBy(
Shipment::getRoute,
Collectors.counting()));
// 7. ID 인덱싱
Map<Long, Shipment> byId = shipments.stream()
.collect(Collectors.toMap(Shipment::getId, s -> s));
// 8. 불변 상수
private static final Set<ShipmentStatus> COMPLETED_STATES = Set.of(
ShipmentStatus.DELIVERED,
ShipmentStatus.CANCELLED
);
→ 이 8가지 패턴이 ILIC 코드의 80%.
핵심 메시지:
90% — "고민 없이" 쓸 수 있는 표준
→ ArrayList, HashMap, HashSet, ConcurrentHashMap
→ 시간을 비즈니스 로직에 투자
9% — 특별한 요구사항 만족
→ 정렬, 순서, LRU, Enum, 멀티스레드
→ 알아두면 큰 가치
1% — 드물지만 강력
→ WeakHashMap, ConcurrentSkipListMap 등
→ 면접 + 깊이
0% — 식별해서 피함
→ Legacy 코드 리팩토링
ILIC 의 90:9:1 법칙에서 90% 의 4가지는?
답:
1. ArrayList (List)
2. HashMap (Map, 단일)
3. HashSet (Set)
4. ConcurrentHashMap (Map, 멀티)
→ 매일 만나는 자료구조.
ILIC 코드 리뷰 시 즉시 교체할 것들:
1. Vector
→ ArrayList (단일)
→ CopyOnWriteArrayList (멀티 읽기 위주)
→ synchronizedList (멀티 균형)
2. Hashtable
→ HashMap (단일)
→ ConcurrentHashMap (멀티)
3. Stack 클래스
→ ArrayDeque (push/pop)
4. Properties (예외)
→ Spring @Value 사용
→ application.properties
→ 직접 사용 안 함
공통 이유:
- Java 1.0 시대 (1996)
- 컬렉션 프레임워크 (Java 1.2, 1998) 이전
- 모든 메서드 synchronized
- API 일관성 부족
- 더 나은 대안 존재
// 패턴 1: Vector → ArrayList
- Vector<E> v = new Vector<>();
+ List<E> v = new ArrayList<>();
// 또는 멀티스레드
+ List<E> v = new CopyOnWriteArrayList<>();
// 패턴 2: Hashtable → HashMap
- Hashtable<K, V> m = new Hashtable<>();
+ Map<K, V> m = new HashMap<>();
// 또는 멀티스레드
+ ConcurrentMap<K, V> m = new ConcurrentHashMap<>();
// 패턴 3: Stack → ArrayDeque
- Stack<E> stack = new Stack<>();
+ Deque<E> stack = new ArrayDeque<>();
// 메서드 동일 (push, pop, peek)
// Vector 반환하는 옛 API 처리
Vector<String> legacy = oldApi.getData();
// 즉시 변환
List<String> modern = new ArrayList<>(legacy);
// 이후엔 modern 사용
Vector 와 Hashtable 의 공통점과 차이점은?
답:
공통점:
차이점:
다음 30문항에 즉답할 수 있다면 Phase 2 마스터.
Q1. Java 컬렉션의 두 가지 최상위 인터페이스는?
A1. Iterable<E>, Map<K, V>
Q2. Map 이 Collection 의 자식이 아닌 이유 3가지는?
A2. 본질적 차이 (단일 요소 vs 키-값 쌍), 수학적 추상화 (집합 vs 함수), API 모순 회피
Q3. Iterable 의 역할은?
A3. for-each 가능, iterator() 제공
Q4. NavigableSet 과 NavigableMap 의 의미는?
A4. 정렬된 컬렉션에 추가 메서드 제공 (floor, ceiling, headMap, tailMap, subMap 등)
Q5. ConcurrentMap 인터페이스의 의미는?
A5. 멀티스레드 안전 + 원자적 메서드 (putIfAbsent, computeIfAbsent 등)
Q6. ArrayList 의 1.5배 확장 정책 코드는?
A6. oldCapacity + (oldCapacity >> 1)
Q7. LinkedList 가 List + Deque 둘 다 구현하는 의미는?
A7. List 처럼 인덱스 접근, Deque 처럼 양 끝 작업, 하나의 클래스가 두 역할
Q8. Vector 안 쓰는 이유 7가지?
A8. Legacy, synchronized 비용, 복합 작업 안전성 부족, 더 나은 대안, 확장 정책 비효율, API 일관성 부족, Stack 자식의 문제
Q9. CopyOnWriteArrayList 의 메커니즘은?
A9. 쓰기 시 전체 배열 복사 + volatile 참조 교체, 읽기 락-프리
Q10. RandomAccess 인터페이스는?
A10. 마커 인터페이스, "인덱스 접근 빠름" 표시, ArrayList O, LinkedList X
Q11. HashSet 의 내부는?
A11. HashMap 의 wrapper (키 = Set 요소, 값 = PRESENT)
Q12. TreeSet 의 내부 구조는?
A12. TreeMap (Red-Black Tree) 의 wrapper
Q13. LinkedHashSet 이 어떻게 순서 유지하나?
A13. LinkedHashMap 의 wrapper, 이중 연결 리스트로 삽입 순서 보존
Q14. hashCode + equals 계약 4가지는?
A14. equals true → hashCode 같음, 반사성, 대칭성, 추이성, 일관성
Q15. EnumSet 의 이점은?
A15. 비트벡터 사용, 매우 메모리 효율, O(1) 모든 작업
Q16. Queue 메서드 페어 (강제/안전) 6가지는?
A16. add/offer, remove/poll, element/peek
Q17. ArrayDeque 가 LinkedList 보다 빠른 이유는?
A17. 원형 배열 (연속 메모리), 캐시 효율, Node 객체 없음, 메모리 효율
Q18. PriorityQueue 의 내부 구조는?
A18. Binary Heap (배열 기반), O(log n) 삽입/제거
Q19. BlockingQueue 의 메서드 페어 4가지는?
A19. add/offer/put/offer(timeout), remove/poll/take/poll(timeout)
Q20. Stack 클래스 안 쓰고 ArrayDeque 쓰는 이유는?
A20. Stack 은 Vector 상속 Legacy, ArrayDeque 는 빠르고 push/pop 지원
Q21. HashMap 의 LoadFactor 0.75 의 의미는?
A21. 75% 차면 2배 확장, 메모리/충돌 균형점
Q22. Java 8+ HashMap 의 트리 변환 조건은?
A22. 한 버킷의 노드 > 8 → 트리 (Red-Black), 트리 < 6 → 다시 연결 리스트
Q23. LinkedHashMap 의 accessOrder=true 의 의미는?
A23. 접근 (get) 시도 노드를 끝으로 이동, LRU 캐시 구현 가능
Q24. ConcurrentHashMap 의 Java 7 vs Java 8 차이는?
A24. Java 7: Segment 16개 락, Java 8+: 노드 락 + CAS, 더 세밀한 동시성
Q25. ConcurrentHashMap 이 null 거부하는 이유는?
A25. get 결과의 모호성 (키 없음 vs null 값) 회피
Q27. 정렬된 키 + 범위 검색이 필요할 때 자료구조는?
A27. TreeMap (NavigableMap), subMap/headMap/tailMap 사용
Q28. 이벤트 리스너 패턴에 적합한 컬렉션은?
A28. CopyOnWriteArrayList 또는 CopyOnWriteArraySet (멀티스레드 읽기 위주)
Q29. Map 의 view 3가지는?
A29. keySet(), values(), entrySet()
Q30. for-each 안에서 list.remove() 시 발생하는 예외와 해결법은?
A30. ConcurrentModificationException, Iterator.remove() 또는 removeIf 사용
30 / 30 → Phase 2 마스터
25-29 → 거의 마스터, 약점 복습
20-24 → 핵심 개념 다시
< 20 → Unit 2.1 ~ 2.5 재학습
Phase 2 졸업 시험에서 가장 어려운 영역은?
답: (개인차)
→ 이 부분을 다시 복습.
다음: Phase 3 — 해시(Hash)의 원리
Phase 3 의 4 Unit:
Unit 3.1 — 해시의 탄생 배경
Unit 3.2 — 해시 충돌 (Hash Collision)
Unit 3.3 — 충돌 해결법 1: 체이닝 (Chaining)
Unit 3.4 — 충돌 해결법 2: 오픈 어드레싱 (Open Addressing)
Phase 2 → Phase 3 의 연결:
Phase 2 에서 "HashMap 은 O(1)" 사용했다면,
Phase 3 에서 "왜 O(1)?" 의 메커니즘 깊이 파기
Phase 3 마스터하면:
1. HashMap 의 내부를 직접 구현 가능
2. 해시 함수의 좋은 조건 제시
3. 충돌 해결법 2가지 비교
4. 면접 단골 "HashMap 구현하시오" 즉답
5. 1주차 HashMap PPT 학습이 정점 완성
다음 중 자신 있는지 체크:
기본 (15개):
☐ List/Set/Queue/Map 구분
☐ ArrayList vs LinkedList 비교
☐ HashSet 의 내부 (HashMap wrapper)
☐ TreeSet 의 Red-Black Tree
☐ LinkedHashSet 의 이중 연결
☐ ArrayDeque vs LinkedList
☐ PriorityQueue 의 Binary Heap
☐ BlockingQueue 의 차단 메서드
☐ HashMap 의 LoadFactor
☐ LinkedHashMap 의 accessOrder
☐ TreeMap 의 NavigableMap
☐ ConcurrentHashMap 의 락 단위
☐ Vector / Hashtable / Stack Legacy
☐ EnumSet / EnumMap 의 비트벡터
☐ List.of / Map.of / Set.of 불변
심화 (10개):
☐ hashCode + equals 계약
☐ Java 8+ 트리 변환 조건
☐ ConcurrentHashMap Java 7 vs 8
☐ amortized O(1) 의 의미
☐ RandomAccess 마커 인터페이스
☐ Map 의 view 3가지
☐ for-each + remove 함정
☐ Arrays.asList 함정
☐ subList 의 view 특성
☐ Iterator vs ListIterator
실전 (5개):
☐ 시나리오 → 자료구조 → 구현체 결정
☐ ILIC 90:9:1 적용
☐ Legacy 코드 리팩토링
☐ 멀티스레드 컬렉션 선택
☐ 큰 컬렉션 초기 크기 지정
🚀 Phase 2 — 컬렉션 프레임워크 전체 지도
✅ Unit 2.1 배열의 한계와 컬렉션의 등장
✅ Unit 2.2 Set 3형제
✅ Unit 2.3 List 3형제
✅ Unit 2.4 Queue
✅ Unit 2.5 Map 5형제
✅ Unit 2.6 컬렉션 전체 지도 정리 ← 여기, Phase 2 완주
→ 매일 코드 작성과 리뷰에 즉시 적용 가능
✅ Phase 1 — Pass by Value (1.1 ~ 1.3 완주)
✅ Phase 2 — 컬렉션 프레임워크 (2.1 ~ 2.6 완주)
🚀 Phase 3 — 해시의 원리 (다음)
⏭ Phase 4 — 추상화의 두 도구
⏭ Phase 5 — 제네릭과 와일드카드
⏭ Phase 6 — 객체 비교
⏭ Phase 7 — I/O 시스템 큰 그림
⏭ Phase 8 — Stream 실전
⏭ Phase 9 — I/O 강화
⏭ Phase 10 — 함수형 프로그래밍
작성한 학습 자료:
Phase 1 (3개): Unit 1.1, 1.2, 1.3
Phase 2 (6개): Unit 2.1, 2.2, 2.3, 2.4, 2.5, 2.6
총: 9/43 Unit 작성 (Phase 2 완주, 약 21%)
Phase 2 에서 "HashMap 은 O(1)" 을 사용했다면, Phase 3 는 그 이유의 깊이.
Phase 3 — 해시의 원리
Unit 3.1 — 해시의 탄생 배경
→ "순차 검색 O(n) 의 한계"
→ "수학적으로 위치 바로 찾기"
→ 해시 함수의 정의
Unit 3.2 — 해시 충돌 (Hash Collision)
→ 비둘기집 원리
→ 충돌이 불가피한 이유
→ Perfect Hashing 의 한계
Unit 3.3 — 충돌 해결법 1: 체이닝 (★ 마스터 프롬프트 깊이)
→ 자바 HashMap 의 채택
→ 연결 리스트 + 트리 (Java 8+)
→ 직접 구현
Unit 3.4 — 충돌 해결법 2: 오픈 어드레싱 (★ 마스터 프롬프트 깊이)
→ 선형 탐사, 이차 탐사, 이중 해싱
→ 메모리 효율 vs 클러스터링
→ 삭제 시의 함정
Phase 2:
"HashMap 을 사용한다"
"ConcurrentHashMap 의 락 단위"
"Set 의 hashCode 의존"
Phase 3:
"왜 HashMap 이 O(1) 인가?"
"해시 함수의 좋은 조건"
"충돌이 발생하면 어떻게 처리?"
"체이닝 vs 오픈 어드레싱"
→ "사용" 에서 "구현" 으로.