TIL - Collection (09.26)
2025. 9. 26. 17:52

📚 오늘 공부한 내용 - 컬렉션 유틸리티 & 전체 정리

🛠️ Collections 클래스 - 유용한 도구들

정렬 관련 메서드

List<Integer> list = new ArrayList<>();
list.add(1); list.add(2); list.add(3); list.add(4); list.add(5);

// 최댓값/최솟값 찾기
Integer max = Collections.max(list);  // 5
Integer min = Collections.min(list);  // 1

// 컬렉션 섞기 (랜덤)
Collections.shuffle(list); // [2, 4, 1, 5, 3] (매번 다름)

// 정렬
Collections.sort(list);    // [1, 2, 3, 4, 5]

// 역순 정렬
Collections.reverse(list); // [5, 4, 3, 2, 1]

핵심 유틸리티 기능들

  • max/min: 정렬 기준으로 최댓값/최솟값 반환
  • shuffle: 컬렉션을 랜덤하게 섞음
  • sort: 정렬 기준으로 컬렉션 정렬
  • reverse: 현재 순서를 뒤집음 (정렬 기준의 반대가 아님!)

🔒 불변 컬렉션 생성

편리한 불변 컬렉션 (Java 9+)

// of() 메서드로 간단 생성
List<Integer> list = List.of(1, 2, 3);
Set<Integer> set = Set.of(1, 2, 3);
Map<Integer, String> map = Map.of(1, "one", 2, "two");

System.out.println("list class = " + list.getClass());
// java.util.ImmutableCollections$ListN

// 변경 시도하면 예외 발생
// list.add(4); // UnsupportedOperationException

빈 컬렉션 생성

// 빈 불변 컬렉션
List<Integer> empty1 = Collections.emptyList(); // Java 5+
List<Integer> empty2 = List.of();               // Java 9+ (권장)

// 빈 가변 컬렉션  
List<Integer> mutable1 = new ArrayList<>();
List<Integer> mutable2 = new LinkedList<>();

권장사항: Java 9 이상에서는 List.of()가 더 간결하고 일관성 있음


🔄 가변 ↔ 불변 컬렉션 전환

// 불변 리스트 생성
List<Integer> immutableList = List.of(1, 2, 3);

// 불변 → 가변 전환
ArrayList<Integer> mutableList = new ArrayList<>(immutableList);
mutableList.add(4); // 변경 가능
System.out.println("mutableList = " + mutableList);

// 가변 → 불변 전환
List<Integer> backToImmutable = Collections.unmodifiableList(mutableList);
// backToImmutable.add(5); // UnsupportedOperationException

Arrays.asList()의 특이한 점

List<Integer> list = Arrays.asList(1, 2, 3);

// 특징: 크기는 고정, 요소는 변경 가능
list.set(0, 10);     // ✅ 가능 - 기존 위치 요소 변경
// list.add(4);      // ❌ 불가능 - 크기 변경
// list.remove(0);   // ❌ 불가능 - 크기 변경

// 애매한 컬렉션이므로 List.of() 권장
List<Integer> better = List.of(1, 2, 3); // 완전 불변

🔐 멀티스레드 동기화

ArrayList<Integer> list = new ArrayList<>();
list.add(1); list.add(2); list.add(3);

// 동기화된 리스트로 변환
List<Integer> synchronizedList = Collections.synchronizedList(list);
System.out.println("synchronizedList class = " + 
    synchronizedList.getClass());
// java.util.Collections$SynchronizedRandomAccessList

특징:

  • 멀티스레드 환경에서 안전하게 사용 가능
  • 동기화 작업으로 인해 성능은 느려짐
  • 멀티스레드 학습 후 상세히 이해 가능

🏛️ 컬렉션 프레임워크 전체 아키텍처

계층 구조 다이어그램

                    Iterable
                       ↓
                   Collection ────────────── Map
                       ↓                     ↓
        ┌──────────────┼──────────────┐     ├── HashMap
      List           Set            Queue    ├── TreeMap  
        ↓              ↓              ↓     └── LinkedHashMap
    ArrayList      HashSet        ArrayDeque
    LinkedList     TreeSet        LinkedList
                   LinkedHashSet

Collection 인터페이스의 핵심 역할

1. 일관성 (Consistency)

// 모든 컬렉션 타입이 동일한 메서드 제공
Collection<String> list = new ArrayList<>();
Collection<String> set = new HashSet<>();
Collection<String> queue = new ArrayDeque<>();

// 동일한 방식으로 사용 가능
list.add("item");   set.add("item");   queue.add("item");
list.size();        set.size();        queue.size();
list.isEmpty();     set.isEmpty();     queue.isEmpty();

2. 재사용성 (Reusability)

// 하나의 메서드로 모든 컬렉션 처리
public static void printSize(Collection<?> collection) {
    System.out.println("Size: " + collection.size());
}

printSize(new ArrayList<>());  // List 처리
printSize(new HashSet<>());    // Set 처리  
printSize(new ArrayDeque<>()); // Queue 처리

3. 다형성 (Polymorphism)

// 런타임에 실제 구현체가 결정됨
public static Collection<String> createCollection(String type) {
    switch(type) {
        case "list": return new ArrayList<>();
        case "set": return new HashSet<>();
        case "queue": return new ArrayDeque<>();
        default: throw new IllegalArgumentException();
    }
}

주요 메서드들

  • add(E e): 요소 추가
  • remove(Object o): 요소 제거
  • size(): 요소 개수 반환
  • isEmpty(): 비어있는지 확인
  • contains(Object o): 요소 포함 여부 확인
  • iterator(): 반복자 반환
  • clear(): 모든 요소 제거

📊 실무 선택 가이드

상황별 최적 구현체

요구사항 추천 구현체 이유

일반적인 리스트 ArrayList 빠른 접근, 메모리 효율
앞쪽 삽입/삭제 빈번 LinkedList O(1) 앞쪽 연산
중복 제거 HashSet O(1) 검색/삽입
순서 유지 + 중복 제거 LinkedHashSet 입력 순서 보장
정렬된 집합 TreeSet 자동 정렬 유지
키-값 저장 HashMap O(1) 검색/삽입
순서 유지 + 키-값 LinkedHashMap 입력 순서 보장
정렬된 키-값 TreeMap 키 기준 정렬
스택/큐 구조 ArrayDeque 최고 성능

실무 기본 선택 (90% 상황)

// 가장 많이 사용되는 조합
List<String> list = new ArrayList<>();      // 순서 있는 데이터
Set<String> set = new HashSet<>();          // 중복 없는 데이터
Map<String, Object> map = new HashMap<>();  // 키-값 쌍 데이터
Deque<String> deque = new ArrayDeque<>();   // 스택/큐 구조

🎯 설계 원칙과 패턴

1. 인터페이스 기반 설계

// ✅ 권장: 인터페이스 타입 선언
List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();

// ❌ 비권장: 구체 클래스 타입 선언  
ArrayList<String> list = new ArrayList<>();
HashMap<String, Integer> map = new HashMap<>();

2. 전략 패턴 적용

  • 정렬: Comparable(기본 전략) + Comparator(대체 전략)
  • 반복: Iterator 패턴으로 순회 전략 추상화
  • 구현체: 동일 인터페이스의 다양한 구현 전략

3. 팩토리 패턴 활용

// Collections의 팩토리 메서드들
List<String> emptyList = Collections.emptyList();
List<String> singletonList = Collections.singletonList("item");
Map<String, Integer> emptyMap = Collections.emptyMap();

🔍 컬렉션 프레임워크의 3대 구성요소

1. 인터페이스 (Interface)

  • 역할: 추상적인 데이터 타입 정의
  • 예시: Collection, List, Set, Queue, Map
  • 장점: 구현에 독립적인 프로그래밍

2. 구현 (Implementation)

  • 역할: 인터페이스의 구체적인 구현체
  • 예시: ArrayList, HashMap, TreeSet 등
  • 특징: 각각 다른 성능 특성과 용도

3. 알고리즘 (Algorithm)

  • 역할: 데이터 처리 및 조작 기능
  • 위치: 각 구현체 + Collections/Arrays 클래스
  • 예시: 정렬, 검색, 순환, 변환 등

💡 핵심 깨달음

"만드는 사람이 수고로우면 쓰는 사람이 편하다"

컬렉션 프레임워크는 이 철학을 완벽히 보여주는 사례입니다:

  • Java 설계자들의 수고: 복잡한 자료구조와 알고리즘 구현
  • 개발자의 편리함: 간단한 메서드 호출로 모든 기능 사용

추상화의 계층

사용자 코드
    ↓
인터페이스 (List, Set, Map...)
    ↓  
구현체 (ArrayList, HashMap...)
    ↓
내부 알고리즘 (정렬, 해싱, 트리...)

각 계층이 명확히 분리되어 관심사의 분리가 잘 이루어짐

확장성과 유지보수성

  • 새로운 구현체 추가: 기존 코드 변경 없음
  • 성능 개선: 내부 구현만 변경, API 동일 유지
  • 기능 확장: 새로운 인터페이스/메서드 추가

🎯 오늘의 핵심 포인트

  1. Collections 유틸리티: 정렬, 섞기, 최댓값/최솟값 등 편의 기능
  2. 불변 컬렉션: List.of() 등으로 안전하고 간편한 생성
  3. 전환의 유연성: 가변 ↔ 불변 컬렉션 간 자유로운 변환
  4. 일관된 설계: Collection 인터페이스 중심의 통합 아키텍처
  5. 실용적 선택: 90% 상황에서 ArrayList, HashMap, HashSet, ArrayDeque

'🧑‍💻Sparta' 카테고리의 다른 글

TIL - DDD 첫 설계 (10.28)  (0) 2025.10.28
TIL - PUT 과 PATCH 멱등성 (10.14)  (0) 2025.10.14
TIL - Comparator (09.25)  (0) 2025.09.25
TIL - Iterator (09.24)  (0) 2025.09.24
TIL - Deque (09.23)  (0) 2025.09.23