본문 바로가기
-- 오늘 있었던 개발 일기

자바의 Collections Framework에 대해

by code study 2025. 12. 15.

Java Collections Framework

Collections Framework란?

자바에서 데이터를 효율적으로 저장하고 관리하기 위한 표준화된 자료구조 클래스들의 모음입니다. 배열의 한계를 극복하고, 다양한 상황에 맞는 자료구조를 제공합니다.

주요 인터페이스 계층 구조

Collection (인터페이스)
├── List (순서 O, 중복 O)
│   ├── ArrayList
│   ├── LinkedList
│   └── Vector
├── Set (순서 X, 중복 X)
│   ├── HashSet
│   ├── LinkedHashSet
│   └── TreeSet
└── Queue (FIFO)
    ├── LinkedList
    └── PriorityQueue

Map (인터페이스) - Key-Value 쌍
├── HashMap
├── LinkedHashMap
├── TreeMap
└── Hashtable

1️⃣ List - 순서가 있고 중복 허용

❌ 문제 사항

// 배열 사용 - 크기 고정, 중간 삽입/삭제 어려움
String[] names = new String[3];
names[0] = "김철수";
names[1] = "이영희";
names[2] = "박민수";
// 4번째 사람 추가하려면? 배열 새로 만들어야 함!

// 타입 안정성 없이 사용(제네릭 사용X)
List list = new ArrayList();
list.add("문자열");
list.add(123);  // 아무 타입이나 들어감
String str = (String) list.get(1);  // 런타임 에러!

✅ 올바른 예시

// 제네릭으로 타입 안정성 확보
List<String> names = new ArrayList<>();
names.add("김철수");
names.add("이영희");
names.add("박민수");
names.add("홍길동");  // 크기 자동 증가!

// 조회가 빈번한 경우 - ArrayList
List<Member> members = new ArrayList<>();
Member member = members.get(0);  // O(1) - 빠름

// 삽입/삭제가 빈번한 경우 - LinkedList
List<Order> orders = new LinkedList<>();
orders.add(0, newOrder);  // 맨 앞 삽입 - O(1)

왜 중요한가?

  • ArrayList: 인덱스 접근이 빠름 (O(1)), 조회가 많을 때 사용
  • LinkedList: 삽입/삭제가 빠름 (O(1)), 데이터 변경이 많을 때 사용

2️⃣ Set - 중복을 허용하지 않음

❌ 문제 사항

// List로 중복 제거하려면 직접 체크해야 함
List<String> tags = new ArrayList<>();
if (!tags.contains("Java")) {  // 매번 중복 체크 필요
    tags.add("Java");
}

// 순서가 필요한데 HashSet 사용
Set<String> menuOrder = new HashSet<>();
menuOrder.add("메인");
menuOrder.add("서브");
menuOrder.add("디저트");
// 출력 순서가 보장되지 않음!

✅ 올바른 예시

// 중복 자동 제거 - HashSet
Set<String> tags = new HashSet<>();
tags.add("Java");
tags.add("Spring");
tags.add("Java");  // 중복! 추가 안 됨
System.out.println(tags.size());  // 2

// 입력 순서 유지가 필요하면 - LinkedHashSet
Set<String> menuOrder = new LinkedHashSet<>();
menuOrder.add("메인");
menuOrder.add("서브");
menuOrder.add("디저트");
// 입력 순서대로 출력됨

// 정렬이 필요하면 - TreeSet
Set<Integer> scores = new TreeSet<>();
scores.add(85);
scores.add(92);
scores.add(78);
// 자동 정렬: [78, 85, 92]

왜 중요한가?

  • HashSet: 가장 빠름 (O(1)), 순서 불필요할 때
  • LinkedHashSet: 입력 순서 유지 필요할 때
  • TreeSet: 정렬된 상태 유지 필요할 때 , 삭제는 remove

 

 


3️⃣ Map - Key-Value 쌍으로 저장

Map이란?

키(Key)와 값(Value)을 쌍으로 저장하는 자료구조입니다. 키는 중복될 수 없고, 키를 통해 값을 빠르게 조회할 수 있습니다.

❌ 문제 사항

// 두 개의 배열로 관리 - 동기화 어려움
String[] keys = {"id", "name", "age"};
Object[] values = {1, "김철수", 25};

// 순서가 중요한데 HashMap 사용
Map<String, String> config = new HashMap<>();
config.put("step1", "초기화");
config.put("step2", "처리");
config.put("step3", "완료");
// 순서 보장 안 됨!

✅ 올바른 예시

// 기본적인 Key-Value 저장 - HashMap
Map<String, Member> memberMap = new HashMap<>();
memberMap.put("M001", new Member("김철수"));
memberMap.put("M002", new Member("이영희"));

Member member = memberMap.get("M001");  // O(1) - 빠른 조회

// 입력 순서 유지 - LinkedHashMap
Map<String, String> config = new LinkedHashMap<>();
config.put("step1", "초기화");
config.put("step2", "처리");
config.put("step3", "완료");
// 순서대로 출력됨

// Key 기준 정렬 - TreeMap
Map<String, Integer> scoreBoard = new TreeMap<>();
scoreBoard.put("C팀", 80);
scoreBoard.put("A팀", 95);
scoreBoard.put("B팀", 88);
// A팀 → B팀 → C팀 순서로 정렬됨

왜 중요한가?

  • HashMap: 가장 빠른 조회/삽입 (O(1))
  • LinkedHashMap: 캐시 구현, 순서 유지 필요 시
  • TreeMap: 정렬된 키가 필요할 때

4️⃣ Queue - FIFO (선입선출)

Queue란?

먼저 들어온 데이터가 먼저 나가는(First In First Out) 자료구조입니다. 줄 서기와 같은 개념으로, 대기열 처리에 주로 사용됩니다.

❌ 문제 사항

// List로 큐 흉내내기 - 비효율적
List<String> queue = new ArrayList<>();
queue.add("작업1");
queue.add("작업2");
String first = queue.remove(0);  // O(n) - 앞에서 제거 시 전체 이동!

// 예외 발생하는 메서드 사용
Queue<String> queue = new LinkedList<>();
String item = queue.remove();   // 비어있으면 NoSuchElementException!
String peek = queue.element();  // 비어있으면 NoSuchElementException!

✅ 올바른 예시

// Queue 인터페이스 사용
Queue<String> queue = new LinkedList<>();

// 추가 (뒤에 넣기)
queue.offer("작업1");
queue.offer("작업2");
queue.offer("작업3");

// 꺼내기 (앞에서 빼기) - 제거됨
String first = queue.poll();  // "작업1" 반환, 비어있으면 null

// 확인만 (제거 안 함)
String peek = queue.peek();   // "작업2" 반환, 비어있으면 null

// 크기 확인
int size = queue.size();      // 2
boolean empty = queue.isEmpty();  // false

왜 중요한가?

  • 순서 보장: 먼저 들어온 것이 먼저 처리됨
  • 안전한 메서드: poll(), peek()은 비어있어도 예외 발생 안 함

주요메서드

offer : 뒤에 추가

poll : 앞에서 꺼내기(제거)

peek: 앞에 뭐  있는지 보기(제거 X)


 

Collections Framework 사용 시 이점

이점설명

🔄 크기 자동 조절 배열과 달리 크기가 자동으로 늘어남
🛡️ 타입 안정성 제네릭으로 컴파일 시점에 타입 체크
⚡ 최적화된 알고리즘 각 상황에 맞는 최적의 자료구조 제공
🔧 풍부한 유틸리티 Collections 클래스의 정렬, 검색, 변환 메서드
🤝 일관된 API 모든 컬렉션이 비슷한 메서드 사용 (add, remove, size 등)




핵심 정리

상황추천 컬렉션

순서 있고, 중복 허용, 조회 많음 ArrayList
순서 있고, 삽입/삭제 많음 LinkedList
중복 제거만 필요 HashSet
중복 제거 + 순서 유지 LinkedHashSet
중복 제거 + 정렬 TreeSet
Key로 빠른 조회 HashMap
Key 조회 + 순서 유지 LinkedHashMap
Key 조회 + 정렬 TreeMap
선입선출(FIFO) 처리 Queue (LinkedList)

 

 


적용 과정 체크리스트

컬렉션 선택 시 스스로 질문하기
    ↓
1. 데이터에 순서가 필요한가?
   → Yes: List 또는 LinkedHashSet/LinkedHashMap
   → No: Set 또는 HashMap
    ↓
2. 중복을 허용하는가?
   → Yes: List
   → No: Set
    ↓
3. Key-Value 쌍으로 저장하는가?
   → Yes: Map 계열
   → No: Collection 계열
    ↓
4. 어떤 작업이 많은가?
   → 조회: ArrayList, HashMap
   → 삽입/삭제: LinkedList
   → 정렬: TreeSet, TreeMap
    ↓
5. 제네릭으로 타입을 명시했는가?
   → List<Member>, Map<String, Order> 형태로 사용