[JAVA] 10 컬렉션(List / Set / Map)과 제네릭
컬렉션(Collection)은 여러 데이터를 효율적으로 관리하기 위한 자료구조다. 배열의 한계를 보완하며, 자바에서는 List, Set, Map 인터페이스를 중심으로 사용한다.
1. 컬렉션이 필요한 이유
배열은 생성 시 크기가 고정되고, 중간 삽입/삭제가 불편하다. 컬렉션은 이러한 문제를 해결하기 위해 등장했다.
- 크기 자동 조절
- 다양한 자료구조 제공
- 공통 인터페이스 기반 (일관된 사용법)
또한 컬렉션은 실무에서 데이터 처리, 필터링, 정렬, 중복 제거 등에 매우 자주 사용된다.
2. 컬렉션 프레임워크 구조
자바 컬렉션은 인터페이스를 중심으로 구성된다.
- List : 순서 O, 중복 O
- Set : 순서 X(일반적으로), 중복 X
- Map : key-value 구조 (key 중복 X)
주의: Map은 Collection을 상속하지 않지만, 컬렉션 프레임워크의 한 축으로 함께 사용된다.
3. List 인터페이스
List는 순서가 있으며 중복을 허용한다. 인덱스로 접근할 수 있다.
import java.util.*;
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(10);
System.out.println(list);
OUTPUT
[10, 20, 10]
- 인덱스 기반 접근 가능
- 대표 구현체: ArrayList, LinkedList
List 자주 쓰는 메서드
int value = list.get(0); // 10
list.set(1, 30); // [10, 30, 10]
list.remove(0); // [30, 10]
System.out.println(list.size()); // 2
System.out.println(list.contains(10)); // true
ArrayList는 조회(get)가 빠르고, 중간 삽입/삭제가 많으면 비용이 커질 수 있다.
4. Set 인터페이스
Set은 중복을 허용하지 않는다. 인덱스가 없다.
import java.util.*;
Set<Integer> set = new HashSet<>();
set.add(10);
set.add(20);
set.add(10);
System.out.println(set);
OUTPUT
[20, 10]
출력 순서는 보장되지 않을 수 있다(HashSet). 중복은 자동으로 제거된다.
- 대표 구현체: HashSet, TreeSet, LinkedHashSet
- HashSet: 빠른 검색(일반적으로), 순서 보장 X
- LinkedHashSet: 입력 순서 유지
- TreeSet: 정렬된 순서 유지(자동 정렬)
Set 순회
for (int n : set) {
System.out.println(n);
}
Set은 인덱스 개념이 없다.
5. Map 인터페이스
Map은 key-value 쌍으로 데이터를 저장한다. key는 중복될 수 없다.
import java.util.*;
Map<String, Integer> map = new HashMap<>();
map.put("kim", 20);
map.put("lee", 30);
map.put("kim", 25); // 덮어쓰기
같은 key로 값을 넣으면 기존 값이 덮어써진다.
Map 값 조회
int age = map.get("kim");
boolean hasKey = map.containsKey("lee");
System.out.println(age);
System.out.println(hasKey);
OUTPUT
25
true
주의: 존재하지 않는 key를 get하면 null이 나올 수 있다.
Map 순회 (entrySet 추천)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
keySet + get 조합도 가능하지만, entrySet이 일반적으로 더 깔끔하다.
6. 컬렉션과 Wrapper 클래스
컬렉션은 기본형을 직접 저장할 수 없다. Wrapper 클래스를 사용해야 한다.
List<Integer> list2 = new ArrayList<>();
list2.add(10); // 오토박싱(int → Integer)
int x = list2.get(0); // 언박싱(Integer → int)
오토박싱/언박싱은 편하지만, 반복문에서 과도하면 성능에 영향이 있을 수 있다.
7. 제네릭(Generic)
제네릭은 컬렉션에 저장할 타입을 미리 지정하는 문법이다. 컴파일 시점에 타입을 체크할 수 있어 안전하다.
import java.util.*;
List<String> names = new ArrayList<>();
names.add("Kim");
names.add("Lee");
System.out.println(names.get(0));
OUTPUT
Kim
- 타입 안정성 확보
- 형 변환 제거
- 실수로 다른 타입을 넣는 문제를 컴파일 단계에서 차단
8. 제네릭 미사용 문제점
import java.util.*;
List list = new ArrayList();
list.add("Java");
list.add(10);
String s = (String) list.get(1); // 런타임 에러 가능
제네릭이 없으면 타입이 섞일 수 있고, 사용 시 형 변환 오류(ClassCastException)가 발생할 수 있다.
9. 컬렉션 선택 기준 (실무 기준)
- 순서 + 중복 필요 → List
- 중복 제거가 목적 → Set
- 검색/매핑이 목적(key로 값 찾기) → Map
추가 팁:
- 정렬이 필요하면 TreeSet / TreeMap 또는 정렬 메서드 활용
- 입력 순서 유지가 필요하면 LinkedHashSet / LinkedHashMap
- 많이 조회(get)하는 구조면 ArrayList가 무난
10. (중요) Set/Map에서 equals()와 hashCode()
HashSet/HashMap은 내부적으로 hashCode와 equals로 중복 여부를 판단한다. 따라서 사용자 정의 객체를 넣을 때 equals/hashCode를 올바르게 구현해야 한다.
class Person {
String name;
Person(String name) {
this.name = name;
}
}
위처럼 equals/hashCode가 없으면 내용이 같아도 서로 다른 객체로 판단될 수 있다. (다음 글에서 equals/hashCode를 깊게 다루면 연결이 좋다)
정리
- 컬렉션은 배열의 한계를 보완한다.
- List, Set, Map은 용도가 다르다.
- 제네릭은 타입 안정성을 높인다.
- Set/Map은 equals()와 hashCode()가 매우 중요하다.
'Computer Science > Java' 카테고리의 다른 글
| [Java] 자바 컬렉션 프레임워크 완전 정리 (0) | 2026.03.14 |
|---|---|
| [JAVA] 다형성 (0) | 2026.02.15 |
| [JAVA] 08 객체지향(OOP) 4대 특징 (0) | 2026.02.15 |
| [JAVA] 07 클래스와 객체 (0) | 2026.02.15 |
| [JAVA] 06 메서드(Method) (0) | 2026.02.15 |