[Java] 컬렉션 프레임워크(Collection Framework)

u_yonu·2026년 3월 4일

Java

목록 보기
18/18
post-thumbnail

컬렉션 프레임워크

알고리즘 문제를 풀다보면 대부분 처음 고민하게 되는 것은 어떻게 데이터를 받아오고, 정렬하할 것이다.
자바에서 데이터를 어떻게 저장하고, 어떻게 꺼내고, 어떻게 정렬할 것인가'는 거의 항상 컬렉션 프레임워크로 귀결된다.


자료구조(Data Structure)

  • 데이터를 효율적으로 접근하기 위해 선택되는 데이터의 조직 및 저장 형식
  • 데이터 값들의 모음, 값들 간의 관계, 그리고 적용 가능한 연산(검색/삽입/삭제 등)의 집합

자료구조의 분류

  • 정적 자료구조(Static Data Structure): 크기가 고정된 자료 구조
    예) 배열(Array)
  • 동적 자료구조(Dynamic Data Structure): 크기가 변할 수 있는 자료구조
    예) 리스트(List), 스택(Stack), 큐(Queue)

자료구조 선택 기준

  • 데이터 접근 속도
  • 메모리 사용 효율성
  • 삽입/삭제의 효율성
  • 순서 유지 여부
  • 중복 데이터 허용 여부

컬렉션 프레임워크

  • 표준화된 데이터 구조(자료구조)와 이를 처리하기 위한 클래스 / 인터페이스의 집합
  • 데이터를 동적 크기로 관리하고, 삽입 / 삭제 / 검색 / 정렬 등을 효율적으로 처리할 수 있음
  • 제네릭을 지원하여 타입 안정성(Type Safety) 보장
  • 표준화된 메서드 제공

위의 표처럼 다양한 컬렉션 프레임 워크가 있다. 오늘은 그중에서 가장 근간이 되는
List 계열, Set 계열, Map 계열에 대해서 알아보고자 한다.


List 계열

List 계열 컬렉션 특징

  • 순서가 있는 데이터 집합
  • 중복 허용
  • 저장된 순서를 유지
  • 배열과 달리 크기가 동적으로 변함

대표 구현 클래스

  • ArrayList
  • LinkedList
  • Vector

주요 메서드

1) 추가(Add)

반환 타입메서드설명
voidadd(int index, E element)지정한 인덱스에 요소 삽입(뒤 요소는 한 칸씩 밀림)
booleanadd(E e)리스트 끝에 요소 추가(성공 여부 반환)
booleanaddAll(int index, Collection<? extends E> c)지정한 인덱스에 컬렉션의 모든 요소를 삽입
booleanaddAll(Collection<? extends E> c)리스트 끝에 컬렉션의 모든 요소를 추가

2) 삭제/비우기(Remove/Clear)

반환 타입메서드설명
voidclear()리스트의 모든 요소 삭제(비움)

3) 포함 여부(Contains)

반환 타입메서드설명
booleancontains(Object o)특정 요소가 포함되어 있는지 확인
booleancontainsAll(Collection<?> c)컬렉션 c의 모든 요소가 리스트에 포함되어 있는지 확인

4) 주요 메서드: 복사(Copy)

반환 타입메서드설명
static <E> List<E>copyOf(Collection<? extends E> coll)주어진 컬렉션을 복사해 새 리스트를 반환(원본과 별개)

5) 비교 / 동등성(Equals / Hash)

반환 타입메서드설명
booleanequals(Object o)리스트 내용이 같은지 비교(순서 포함)
inthashCode()리스트의 해시값 반환(동등성 규약과 연계)

6) 조회(Get)

반환 타입메서드설명
Eget(int index)해당 인덱스의 요소 반환

7) 검색(Search)

반환 타입메서드설명
intindexOf(Object o)요소 o의 첫 등장 인덱스 반환(없으면 -1)

8) 상태 확인

반환 타입메서드설명
booleanisEmpty()리스트가 비어 있으면 true

ArrayList

  • 배열 기반 구현
  • 인덱스를 통한 접근이 빠름(조회 유리)
  • 중간 삽입/삭제 시 요소 이동 비용 때문에 성능 저하 가능
  • 데이터 조회가 많고, 삽입/삭제가 적을 때

LinkedList

  • 노드 기반 구현(각 노드가 이전 / 다음 노드 참조를 가짐)
  • 삽입 / 삭제가 빠른 편(노드 연결만 변경)
  • 인덱스 접근은 상대적으로 불리할 수 있음
  • 데이터 삽입 / 삭제가 많고, 조회가 상대적으로 적을 때


Set 계열

Set 계열 컬렉션 특징

  • 중복 허용하지 않음
  • 순서 보장하지 않음(구현체에 따라 예외 있음)
  • null 허용(보통 1개)
  • “고유성”이 중요한 데이터에 유용

대표 구현 클래스

  • HashSet
  • LinkedHashSet
  • TreeSet

HashSet

  • 저장 순서 유지 X
  • 내부적으로 HashMap 기반
  • 추가/삭제/검색이 빠름(해시 기반)
  • null 1개 저장 가능

    여기서 쓰이는 Hash라는 용어는 '데이터를 빠르게 저장하고 검색하기 위해서 사용하는 특별한 값 또는 기법'을 말하는데, 이는 데이터를 '고유한 숫자 값'으로 변환하는 과정을 말한다.
    => 여기서 고유한 숫자 = hashCode() 값


LinkedHashSet

  • 저장 순서 유지 O
  • 내부적으로 LinkedHashMap 기반(해시 + 연결 리스트)
  • HashSet보다 약간 느릴 수 있음(연결 리스트 관리 비용)
  • null 1개 저장 가능

TreeSet

  • 데이터가 정렬된 상태로 유지(기본 오름차순)
  • 사용자 정의 정렬이 필요하면 Comparator 사용 가능
  • 내부적으로 레드-블랙 트리(균형 이진 탐색 트리) 기반
  • null 저장 불가(정렬/비교 불가능)

Set 주요 메서드

1) 추가(Add)

반환 타입메서드설명
booleanadd(E e)요소 추가(중복이면 추가되지 않음, 성공 여부 반환)
booleanaddAll(Collection<? extends E> c)컬렉션의 모든 요소를 Set에 추가

2) 삭제 / 비우기(Remove / Clear)

반환 타입메서드설명
booleanremove(Object o)특정 요소 삭제(삭제 성공 여부 반환)
voidclear()Set의 모든 요소 삭제

3) 포함 여부(Contains)

반환 타입메서드설명
booleancontains(Object o)특정 요소가 포함되어 있는지 확인
booleancontainsAll(Collection<?> c)컬렉션 c의 모든 요소가 Set에 포함되어 있는지 확인

4) 복사(Copy)

반환 타입메서드설명
static <E> Set<E>copyOf(Collection<? extends E> coll)주어진 컬렉션을 복사해 새 Set을 반환(원본과 별개)

5) 비교 / 동등성(Equals / Hash)

반환 타입메서드설명
booleanequals(Object o)Set 동등성 비교(순서가 아니라 “구성 요소” 기준)
inthashCode()해시값 반환(동등성 규약과 연계)

6) 상태 확인

반환 타입메서드설명
intsize()Set의 크기(요소 수) 반환
booleanisEmpty()Set이 비어 있으면 true

7) 순회(Iteration)

반환 타입메서드설명
Iterator<E>iterator()Set을 순회할 수 있는 Iterator 반환

Iterator는 한마디로 컬렉션(Set/List 등)"하나씩 꺼내서 순회할 수 있게 해주는 도구(반복자)"로 Set은 인덱스가 없어서(get 메서드 같은 게 없음) 내부 요소를 하나씩 보려면 순회 방법이 필요하고, 그 표준 방식이 iterator()이다.

Set<String> set = new HashSet<>();
set.add("A");
set.add("B");

Iterator<String> it = set.iterator();

while (it.hasNext()) {
  String v = it.next();
  System.out.println(v);
}

for each 구문 또한 iterator 기반의 방법이다.


Map 계열

Map 계열 컬렉션 특징

  • 키(Key)와 값(Value) 의 쌍으로 저장
  • 키는 중복 불가, 값은 중복 가능
  • 키를 통해 빠른 검색 가능
  • null 허용 여부는 구현체에 따라 다름(TreeMap은 null key 불가)

대표 구현 클래스

  • HashMap
  • LinkedHashMap
  • TreeMap

HashMap

  • 저장 순서 유지 X
  • 내부적으로 해시 테이블 사용
  • null 키 1개 허용, null 값 여러 개 허용
  • 빠른 검색/삽입/삭제

LinkedHashMap

  • 저장 순서 유지 O
  • 내부적으로 해시 테이블 + 연결 리스트
  • null 키 1개 허용, null 값 여러 개 허용
  • HashMap과 유사한 성능이지만 순서 관리 비용이 약간 추가될 수 있음

TreeMap

  • 키 기준으로 정렬된 상태 유지(기본 오름차순)
  • Comparator로 사용자 정의 정렬 가능
  • 내부적으로 레드-블랙 트리 기반
  • null 키 허용하지 않음

Map 주요 메서드

1) 추가/수정(Put & Compute)

반환 타입메서드설명
Vput(K key, V value)키-값 쌍 추가(키가 이미 있으면 값이 덮어써짐)
default Vcompute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)키에 대해 새 값을 재계산(없으면 null로 계산될 수 있음)
default VcomputeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)키가 없을 때만 값 생성 후 저장
default VcomputeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)키가 있을 때만 값 재계산 후 저장

2) 조회(Get)

반환 타입메서드설명
Vget(Object key)키에 해당하는 값을 반환(없으면 null)
default VgetOrDefault(Object key, V defaultValue)키가 없으면 기본값 반환

3) 삭제(Remove)

반환 타입메서드설명
Vremove(Object key)키에 해당하는 엔트리 삭제 후 기존 값 반환(없으면 null)

4) 포함 여부(Contains)

반환 타입메서드설명
booleancontainsKey(Object key)특정 키가 존재하는지 확인
booleancontainsValue(Object value)특정 값이 존재하는지 확인

5) 키/값/엔트리 뷰(View)

반환 타입메서드설명
Set<K>keySet()모든 키를 Set 형태로 반환
Collection<V>values()모든 값을 Collection 형태로 반환
Set<Map.Entry<K,V>>entrySet()(키,값) 엔트리 집합을 Set 형태로 반환

6) 복사(Copy)

반환 타입메서드설명
static <K,V> Map<K,V>copyOf(Map<? extends K, ? extends V> map)주어진 Map을 복사해 새 Map을 반환(원본과 별개)

7) 상태 확인

반환 타입메서드설명
intsize()저장된 키-값 쌍(엔트리) 개수 반환
booleanisEmpty()Map이 비어 있으면 true
voidclear()모든 엔트리 삭제

8) 반복/순회(Iteration)

반환 타입메서드설명
default voidforEach(BiConsumer<? super K, ? super V> action)모든 엔트리에 대해 (key,value)로 순회 수행

9) 동등성(Equals / Hash)

반환 타입메서드설명
booleanequals(Object o)Map 동등성 비교(엔트리 구성 기준)
inthashCode()해시값 반환

자료구조를 이용한 정렬(Sort)

  • 요소들을 특정 기준에 맞춰 오름차순 / 내림차순으로 배치하는 것
  • 일반적으로 순서를 가지는 컬렉션(List) 이 정렬 대상이 된다.
  • 배열 정렬: Arrays.sort()
  • 컬렉션 정렬: Collections.sort()
// 배열 정렬
Arrays.sort(arr);

// 리스트 정렬
Collections.sort(list);

=> 실제 정렬은 모두 오름차순이 된다. 따라서 다른 정렬 기준으로 만들기 위해서 '정렬기준'가 필요하다.

정렬기준

자바에서는 객체 정렬 기준을 정의하는 방법은 두가지로 아래와 같다.

  • Comparable : 객체가 '기본 정렬 기준'을 스스로 가짐
  • Comparator : 객체 외부에서 '별도의 정렬 기준'을 만듬

Comparable 인터페이스

  • 객체의 기본정렬 기준을 정의
  • 클래스가 직접 implemets Comparable<T>로 구현
  • compareTo(T o) 메서드를 구현하여 정렬 기준을 정의
    예) 이름 순, 나이 순 등
public interface Comparable<T> {
    public int compareTo(T o);
}

반환값의 의미

  • 0 : 현재 객체와 비교 대상 객체가 같음
  • 양수 : 현재 객체가 비교 대상 객체보다 큼
  • 음수 : 현재 객체가 비교대상 객체보다 작음

구현예시

// 구현예시 
import java.util.Objects;

class Student implements Comparable<Student> {
    private final String name;
    private final int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 기본 정렬 기준: age 오름차순
    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.age, other.age);
    }

    @Override
    public String toString() {
        return name + "(" + age + ")";
    }
}


import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student("Min", 23));
        students.add(new Student("Yonu", 20));
        students.add(new Student("Soo", 21));

        Collections.sort(students); // compareTo 기준으로 정렬
        System.out.println(students);
        // 출력 예: [Yonu(20), Soo(21), Min(23)]
    }
}

Comparator 인터페이스

  • 별도의 정렬 기준을 정의
  • 정렬 기준이 여러개 필요할 때 유용
  • 클래스 외부에서 정렬 기준을 정의하며, 특정 필드 / 사용자 정의 기준으로 정렬 할 수 있음
  • compar(T o1, T o2) 메서드를 구현
public interface Comparator<T> {
    int compare(T o1, T o2);
}

반환값의 의미

  • 0 : 두 객체가 같음
  • 양수 : 첫 번째 객체가 두 번째 객체보다 큼
  • 음수 : 첫 번째 객체가 두 번째 객체보다 작음

구현예시

// 별도 클래스로 만들기
Collections.sort(names, new StringLengthComparator());
// 익명 내부 클래스로 만들기
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return Integer.compare(o1.length(), o2.length());
    }
});
//람다로 만들기
Collections.sort(names, (o1, o2) -> {
    return Integer.compare(o1.length(), o2.length());
});
class Student {
    private final String name;
    private final int age;
    private final double gpa;

    public Student(String name, int age, double gpa) {
        this.name = name;
        this.age = age;
        this.gpa = gpa;
    }

    public String getName() { return name; }
    public int getAge() { return age; }
    public double getGpa() { return gpa; }

    @Override
    public String toString() {
        return name + "(age=" + age + ", gpa=" + gpa + ")";
    }
}
// 별도 클래스로 만들기

import java.util.Comparator;

class AgeAscComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        // o1이 앞이면 음수, o2가 앞이면 양수, 같으면 0
        return Integer.compare(o1.getAge(), o2.getAge());
    }
}

// 익명 클래스
import java.util.*;

Comparator<Student> nameAsc = new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getName().compareTo(o2.getName()); // 이름 오름차순
    }
};
//람다 
import java.util.*;

Comparator<Student> ageAsc = (o1, o2) -> Integer.compare(o1.getAge(), o2.getAge());
Comparator<Student> gpaDesc = (o1, o2) -> Double.compare(o2.getGpa(), o1.getGpa());

Comparable vs Comparator

구분ComparableComparator
목적객체의 기본 정렬 기준(자연 순서) 을 클래스 내부에 정의객체 외부에서 별도의 정렬 기준을 정의
구현 위치정렬 대상 클래스가 implements Comparable<T>별도 클래스/익명 클래스/람다로 Comparator<T> 구현
핵심 메서드int compareTo(T o)int compare(T o1, T o2)
정렬 호출Collections.sort(list) / Arrays.sort(arr)Collections.sort(list, comp) / Arrays.sort(arr, comp)
정렬 기준 개수보통 1개(대표 기준)여러 개 가능 (상황별 기준 교체 쉬움)
클래스 수정 필요필요함 (클래스에 compareTo 추가)불필요 (클래스 밖에서 정의)
재사용성“기본 기준”은 어디서나 자동 적용되어 편함기준을 필요한 곳에서만 선택적으로 적용 가능
유지보수기준이 바뀌면 클래스 수정/재배포 필요기준 변경/추가가 쉬움(정렬 코드만 바꾸면 됨)
장점- 기본 정렬이 명확해짐
- 사용이 간단함(컴퍼레이터 없이 정렬 가능)
- 다양한 정렬 기준을 유연하게 적용
- 클래스 변경 없이 정렬 기준 추가 가능
- 다중 정렬(thenComparing)에 강함
단점- 정렬 기준이 여러 개면 관리가 불편함
- 클래스에 정렬 로직이 섞임
- 매번 Comparator를 전달해야 할 수 있음
- 기준이 많아지면 Comparator 관리가 필요
언제 쓰나“이 클래스의 대표 정렬 기준이 명확”할 때
예: 학번, 날짜, id 등
“정렬 기준이 상황에 따라 달라짐/여러 개 필요”할 때
예: 이름순/나이순/평점순 등

조금 복잡했지만 오늘의 개념 끝.

profile
비전공자의 개발도전기

0개의 댓글