빠른 비교
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Map<String, Integer> map = new HashMap<>();갈리는 기준
어떤 컬렉션을 먼저 고르면 되나
| 상황 | 먼저 떠올릴 것 |
|---|---|
| 순서가 중요하고 중복 허용 | List |
| 중복 제거 | Set |
| 키로 빠르게 조회 | Map |
| 삽입 순서 유지 Map | LinkedHashMap |
| 키 정렬 Map | TreeMap |
List, Set, Map: 정책의 차이
Java 컬렉션은 "데이터를 여러 개 담는 상자"가 아니라, 순서, 중복 허용 여부, 키-값 관계 같은 정책 차이를 타입으로 드러냅니다. 어떤 컬렉션을 고를지는 데이터의 성격에 따라 달라집니다.
// 순서가 중요하고 중복 허용
List<String> orders = new ArrayList<>();
// 중복 제거가 중요
Set<String> uniqueTags = new HashSet<>();
// 키로 빠르게 조회
Map<Long, User> userById = new HashMap<>();구현체 선택과 성능 특성
같은 List라도 ArrayList는 인덱스 접근이 O(1)이지만 중간 삽입이 느리고, LinkedList는 중간 삽입이 빠르지만 인덱스 접근이 O(n)입니다. HashMap은 순서가 없고, LinkedHashMap은 삽입 순서를 유지하며, TreeMap은 키 정렬 순서를 유지합니다.
// 순서 유지가 필요한 Map
Map<String, Integer> scores = new LinkedHashMap<>();
// 키 정렬이 필요한 Map
Map<String, Integer> sorted = new TreeMap<>();인터페이스 타입으로 받기
변수 타입을 구현체(ArrayList)보다 인터페이스(List)로 선언하면, 나중에 구현체를 바꿀 때 호출 코드를 수정하지 않아도 됩니다. 구현체 타입이 중요한 경우(예: LinkedList의 Deque 기능)에만 구체 타입을 씁니다.
List vs Set vs Map을 잘못 고르면 생기는 문제
컬렉션 선택은 단순 취향 문제가 아니라, 중복 처리 방식과 조회 비용을 같이 결정합니다. 처음부터 데이터 성격에 맞게 잡아야 뒤에서 중복 제거 로직이나 선형 탐색을 덜 붙이게 됩니다.
// ❌ 회원 ID를 List에 쌓고 contains로 중복 검사
List<Long> userIds = new ArrayList<>();
if (!userIds.contains(id)) {
userIds.add(id);
}
// ✅ 중복이 핵심이면 Set
Set<Long> userIds = new HashSet<>();
userIds.add(id);
// ❌ 사용자 조회를 List 순회로 해결
User found = users.stream()
.filter(u -> u.getId().equals(id))
.findFirst()
.orElse(null);
// ✅ ID 조회가 핵심이면 Map
Map<Long, User> userById = new HashMap<>();
User found = userById.get(id);선택 기준
| 상황 | 적합한 선택 |
|---|---|
| 순서가 중요하고 중복 허용 | List (ArrayList 기본) |
| 중복 제거가 중요 | Set (HashSet 기본) |
| 키로 빠르게 조회 | Map (HashMap 기본) |
| 삽입 순서 유지 Map | LinkedHashMap |
| 키 정렬 순서 Map | TreeMap |
주의할 점
"여러 개 담아야 하니 일단 List"로 시작하면 중복 처리나 조회 성능에서 나중에 설계를 다시 짜게 됩니다.
// ❌ List로 중복 검사 — O(n) 탐색 반복
List<String> tags = new ArrayList<>();
if (!tags.contains(newTag)) { // O(n)
tags.add(newTag);
}
// ✅ Set으로 중복 자동 제거 — O(1)
Set<String> tags = new HashSet<>();
tags.add(newTag); // 자동으로 중복 무시
// ❌ List에서 ID로 User 찾기 — O(n)
User found = users.stream().filter(u -> u.getId() == id).findFirst().orElse(null);
// ✅ Map으로 O(1) 조회
Map<Long, User> userById = new HashMap<>();
User found = userById.get(id);참고 링크
2 sources