ch12_컬렉션
통합 문서입니다.
1. 컬렉션 프레임워크
컬렉션 프레임워크
학습 목표
- Java 컬렉션 계층(List/Set/Map)의 목적과 차이를 이해할 수 있다.
- 상황별 구현체 선택 기준(성능/중복/순서/정렬)을 설명할 수 있다.
equals/hashCode, 정렬, 반복자, 동시성 이슈를 실무 관점으로 다룰 수 있다.
1. 컬렉션이 필요한 이유
배열은 고정 길이, 단일 타입, 기능 제한이 있다.
컬렉션은 가변 크기 + 풍부한 연산 + 표준 API를 제공한다.
핵심 인터페이스:
ListSetMap
2. List
특성:
- 순서 보장
- 중복 허용
- 인덱스 접근 가능
대표 구현:
ArrayList: 조회 빠름, 중간 삽입/삭제 느림LinkedList: 중간 삽입/삭제 유리, 인덱스 조회 비효율
3. Set
특성:
- 중복 불가
- 순서 보장 여부는 구현체마다 다름
대표 구현:
HashSet: 해시 기반, 일반적으로 빠름LinkedHashSet: 입력 순서 유지TreeSet: 정렬 상태 유지(log n)
4. Map
특성:
- key-value 쌍
- 키 중복 불가, 값 중복 가능
대표 구현:
HashMap: 일반적으로 빠른 키 조회LinkedHashMap: 삽입 순서 유지(LRU 구현에도 활용)TreeMap: 키 정렬 유지
5. 성능 관점 기초
일반적인 평균 복잡도:
ArrayList조회: O(1), 중간 삽입: O(n)HashSet/HashMap탐색: O(1) 평균TreeSet/TreeMap탐색: O(log n)
주의:
- 해시 충돌, 리사이징, 데이터 분포에 따라 실제 성능은 달라질 수 있다.
6. equals/hashCode 계약 (매우 중요)
Set/Map 키에서 객체 동등성은 equals/hashCode 계약에 의존한다.
규칙:
equals가 true면hashCode도 동일해야 함- 객체 상태가 변해
hashCode가 바뀌면 컬렉션 동작이 깨질 수 있음
값 객체를 키로 쓸 때는 불변 설계가 유리하다.
7. 반복과 수정
for-each 순회 중 구조 변경 시 ConcurrentModificationException이 발생할 수 있다.
안전한 삭제:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (it.next().isBlank()) it.remove();
}
8. 정렬
8.1 자연 정렬 Comparable
객체 내부에 기본 정렬 기준을 정의.
8.2 사용자 정의 정렬 Comparator
상황별 정렬 전략을 외부에서 주입.
list.sort(Comparator.comparing(User::getAge).thenComparing(User::getName));
9. 불변 컬렉션
List<String> fixed = List.of("A", "B");
특징:
- 구조 변경 불가(add/remove 예외)
- 읽기 전용 데이터 전달에 적합
10. 동시성 컬렉션
멀티스레드 환경에서 일반 컬렉션은 안전하지 않다.
대안:
ConcurrentHashMapCopyOnWriteArrayListCollections.synchronizedList(...)(상황에 따라)
동시성 패턴에 맞는 컬렉션 선택이 필요하다.
11. 실무 선택 가이드
- 기본 목록:
ArrayList - 중복 제거:
HashSet - 키 조회:
HashMap - 정렬 상태 유지 필요:
TreeMap/TreeSet - 순서 보존 + 키 조회:
LinkedHashMap
12. 정리
- 컬렉션 선택은 습관이 아니라 요구사항 기반 의사결정이다.
- 중복, 순서, 정렬, 조회 패턴, 동시성 요구를 함께 고려해야 한다.
equals/hashCode와 정렬 기준이 컬렉션 안정성을 좌우한다.
2. 문제
문제
ch12 범위(List/Set/Map, 정렬, equals/hashCode, 반복자) 문제입니다.
A. List
- 정수
List에서 최댓값/최솟값/평균을 구하시오. - 리스트 중간 삽입/삭제를 구현하고 인덱스 변화를 확인하시오.
- 중복 요소를 유지한 채 빈도수를 계산하시오.
B. Set
- 문자열 리스트에서 중복을 제거하시오.
- 두
Set의 합집합/교집합/차집합을 구하시오. LinkedHashSet과HashSet의 출력 순서를 비교하시오.
C. Map
- 문장에서 단어 빈도수(
Map<String, Integer>)를 집계하시오. - 키가 없는 경우 기본값 처리(
getOrDefault)를 적용하시오. entrySet순회로 키/값을 출력하시오.
D. 정렬
- 사용자 객체 리스트를 나이 오름차순으로 정렬하시오(
Comparator). - 이름 오름차순 + 나이 내림차순 복합 정렬을 구현하시오.
TreeSet/TreeMap에서 정렬 기준이 어떻게 적용되는지 확인하시오.
E. equals/hashCode
- 사용자 정의 클래스
User(id, name)를HashSet에 넣어 중복 판별하시오. equals/hashCode미구현 시 문제를 재현하고 수정하시오.- mutable 필드를 해시 키로 썼을 때 문제를 재현하시오.
F. 반복자/수정
- 리스트 순회 중 조건에 맞는 요소를 안전하게 제거하시오(
Iterator). for-each중 구조 변경 시 예외가 나는 코드와 수정 코드를 작성하시오.
G. 챌린지
- 전화번호부 시스템(
Map<String, Contact>)을 작성하시오. - 최근 조회 순서를 유지하는 캐시(
LinkedHashMap)를 구현하시오. - 멀티스레드 환경에서
ConcurrentHashMap으로 안전 집계를 구현하시오.
제출 체크리스트
- 요구사항(중복/순서/정렬/조회패턴)에 맞는 컬렉션을 선택했는가?
- 사용자 정의 객체의 동등성 계약을 맞췄는가?
- 순회 중 수정 시 안전한 패턴을 사용했는가?