[JAVA] 10 컬렉션(List / Set / Map)과 제네릭

[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