Java

[JAVA] 컬렉션 총정리

생선묵김치찌개 2025. 1. 13. 01:56

💡 JCF란?

- JCF(Java Collection FrameWork) : 자료 구조 종류의 형태들을 자바 클래스로 구현한 모음집
- JCF의 계층 구조

JCF의 계층 구조

➜ List, Queue, Set과 달리 Map은 두개의 데이터를 묶어 한쌍으로 다루기 때문에 Collection 클래스와는 분리되어 있다.
Vector, Stack, HashTable과 같은 클래스들은 레거시 임으로 사용 하지 않는다
 

💡 List 인터페이스 (ArrayList., LinkedList, Vector)

- 순서가 있는 데이터 집합
- 같은 요소의 중복 저장 허용
- 배열과 마찬가지로 index로 접근
- List vs 배열 : 리스트는 자료형 크기가 고정이 아니라 데이터 양에 따라 동적으로 늘어났다 주는것에 반해 배열은 고정되어 있다.
- 내부적으로 요소 사이에 빈공간을 허용하지 않아 삽입 삭제 할때마다 배열 이동이 일어난다.
 

(ArrayList 클래스)

ArrayList 자료구조

- 배열을 기반으로 만든 List
- 데이터량에 따라 특정 양을 넘어서면 공간이 자동으로 늘었다가 줄음
- 조회가 빠르다, But 데이터를 삽입, 삭제 할 때 모든 데이터를 밀고 당겨야 해서 삽입 삭제 성능이 느리다
- Thread Safe 하지 않음

(LinkedList 클래스)

LinkedList 자료구조 (but 노드가 양방향 가르킴)

 
- 노드를 기반으로 민든 리스트
- 자바의 LinkedList의 노드는 양방향 포인터 구조로 되어 있다 
- 데이터를 삽입, 삭제 할 경우, 그냥 노드를 끼워 넣으면 되기 때문에 빠르다. But 조회의 경우 앞에서부터 타고 가면서 찾아야 하기 때문에 성능이 느리다.
- Thread Safe 하지 않음
- 기본적으로 LinkedList로 구성 되어 있는데, 데이터가 일정 이상으로 들어오면 Red Black Tree로 자료구조가 변경된다.
 
ArrayList, LinkedList를 Thread Safe 하게 사용하려면?
1. Collections.synchronizedList() 사용

List<String> syncList = Collections.synchronizedList(new ArrayList<>());

 
2. CopyOnWriteArrayList 사용

List<String> threadSafeList = new CopyOnWriteArrayList<>();

 

(Vector 클래스)
- 레거시로 이제 사용하지 않는다
- 모든 메서드가 동기화 되어 있어 Thread Safe 하다
 
 

💡 Queue 인터페이스 (PriorityQueue, Deque, ArrayDeque)


- 선입선출 FIFO(First-In-First-Out) 구조 

 

(PriorityQueue 클래스)

- 우선순위를 가지는 큐
- 우선순위가 높은 순으로 정렬되고 꺼낸다
- 우선순위 큐에 저장할 객체는 Comparable 클래스를 구현 해야 함 


(Deque 인터페이스)

Deque 자료구조

- 앞뒤 다 넣고 빼는것이 가능한 큐


(ArrayDeque 클래스)

- Deque의 구현체

Deque<Integer> deque = new ArrayDeque<>();

deque.offerLast(100); // [100]
deque.offerFirst(10); // [10, 100]
deque.offerFirst(20); // [20, 10, 100]
deque.offerLast(30); // [20, 10, 100, 30]

deque.pollFirst(); // 20 <- [10, 100, 30]
deque.pollLast(); // [10, 100] -> 30
deque.pollFirst(); // 10 <- [100]
deque.pollLast(); // [] -> 100

 
 

💡 Set 인터페이스 (HashSet, LinkedHashSet, TreeSet)

Set 인터페이스의 구현체들
Set의 특징

- 데이터의 중복을 허용하지 않고 순서를 유지하지 않는 데이터의 집합
- 순서 자체가 없으므로 인덱스로 객체를 검색해서 가져오는 get(index) 메서드도 존재하지 않는다
- null도 중복으로 쳐서 null도 하나만 저장 가능
- Hashcode를 기반으로 중복을 판단하기 때문에 hashCode()를 적절히 재정의 하지 않은 경우 문제가 발생할 수도 있다.
 


(HashSet 클래스)


- Hash 기반으로 구현된, 아무 추가 기능이 없는 Set
- Set의 기본 특성인 데이터 중복을 허용하지 않는 속성만 가지고 있음
- 순서를 전혀 예측할 수 없다
 

Set<Integer> hashSet = new HashSet<>();

hashSet.add(10);
hashSet.add(20);
hashSet.add(30);
hashSet.add(10); // 중복된 요소 추가

hashSet.size(); // 3 - 중복된건 카운트 X

hashSet.toString(); // [20, 10, 30] - 자료 순서가 뒤죽박죽

 
 


(LinkedHashSet 클래스)


- Hash 기반으로 구현된, 순서를 가지는 Set
- 순서가 삽입된 순서이다

public class LinkedHashSetExample {
    public static void main(String[] args) {
        Set<String> linkedHashSet = new LinkedHashSet<>();

        // 요소 추가
        linkedHashSet.add("Apple");
        linkedHashSet.add("Banana");
        linkedHashSet.add("Cherry");
        linkedHashSet.add("Apple");  // 중복 요소 (무시됨)

        // 요소 출력 (삽입 순서 유지) - [Apple, Banana, Cherry]
        System.out.println("LinkedHashSet: " + linkedHashSet);
    }
}

 
 


(TreeSet 클래스)


- 이진 검색 트리 자료구조의 형태로 데이터를 저장
- 중복 허용 X, 요소를 오름차순(default)으로 정렬
- null 값 허용하지 않음

public class TreeSetExample {
    public static void main(String[] args) {
        Set<Integer> set = new TreeSet<>();
        set.add(30);
        set.add(10);
        set.add(20);
        set.add(10); // 중복된 값은 무시됨
        
        System.out.println(set); // [10, 20, 30] - 정렬된 순서
    }
}

 
 

💡 Map 인터페이스 (HashMap, LinkedHashMap, TreeMap)

Map 인터페이스의 구현체들

 
- 키(Key)와 값(value)의 쌍으로 연관지어 이루어진 데이터의 집합
- 값(value)은 중복되서 저장될 수 있지만, 키(key)는 해당 Map에서 고유해야만 한다
- 기존에 저장된 데이터와 중복된 키로 다른 값을 한번 더 저장하면, 이전 값이 새로운 값으로 덮어씌워진다
 


(HashMap)


- 중복을 허용하지 않고 순서를 보장하지 않는다
- 멀티 스레드 환경에서는 ConcurrentHashMap을 사용하자

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();

        // 데이터 추가
        map.put("Alice", 25);
        map.put("Bob", 30);
        map.put("Charlie", 35);

        System.out.println("Alice의 나이: " + map.get("Alice")); // 출력: Alice의 나이: 25
        System.out.println("Bob이 존재합니까? " + map.containsKey("Bob")); // 출력: Bob이 존재합니까? true
        System.out.println("30이라는 나이가 존재합니까? " + map.containsValue(30)); // 출력: 30이라는 나이가 존재합니까? true
        System.out.println("모든 키: " + map.keySet()); // 출력: 모든 키: [Alice, Bob, Charlie]
        System.out.println("모든 값: " + map.values()); // 출력: 모든 값: [25, 30, 35]
        map.remove("Charlie");
        System.out.println("Charlie 삭제 후: " + map);
        System.out.println("HashMap 크기: " + map.size()); // 출력: HashMap 크기: 2
   }
}

+ HashMap은 해시함수를 이용하여 Key값을 특정 인덱스(해시값)으로 변환하고, 빈 공간 내에 해시 값을 저장한다.

bucket은 값

 


(LinkedHashMap)


- 일반적으로 Map 자료구조는 순서를 가지지 않지만, LinkedHashMap은 들어온 순서대로 순서를 가진다.

public static void main(String[] args) {
        LinkedHashMap<Integer, String> map = new LinkedHashMap<>();

        // 데이터 삽입
        map.put(3, "Three");
        map.put(1, "One");
        map.put(2, "Two");

        // 데이터 출력 (삽입 순서 유지) - {3=Three, 1=One, 2=Two}
        System.out.println("LinkedHashMap 내용: " + map);
    }

 


(TreeMap)


- Key 값을 기준으로 정렬된다.

public static void main(String[] args) {
        // TreeMap 생성
        TreeMap<Integer, String> map = new TreeMap<>();

        // 데이터 삽입
        map.put(3, "Three");
        map.put(1, "One");
        map.put(2, "Two");

        // 데이터 출력 (정렬된 순서 유지) - {1=One, 2=Two, 3=Three}
        System.out.println("TreeMap 내용: " + map);
    }

 
 

💡 Iterable 인터페이스

- Iterable 인터페이스는 iterator를 반환하는 iterator() 추상 메서드가 있음
- iterator() 사용법

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        Iterator<String> iterator = list.iterator();

        System.out.println("List 내용:");
        while (iterator.hasNext()) { // 요소가 있는지 확인
            System.out.println(iterator.next()); // 다음 요소 반환
            iterator.remove(); // 요소 삭제
        }
    }
}

 
 

💡 Collections 클래스

- Collections는 Collection 조작을 위한 유틸리티 클래스
- Collections 클래스 사용법

public class Main {
    public static void main(String[] args) {
        // 1. 초기 리스트 생성
        List<Integer> numbers = new ArrayList<>();
        numbers.add(5);
        numbers.add(2);
        numbers.add(8);
        numbers.add(1);
        numbers.add(3);
        // Original list: [5, 2, 8, 1, 3]
        System.out.println("Original list: " + numbers);

        // 2. 정렬 (sort)
        Collections.sort(numbers);
        // Sorted list: [1, 2, 3, 5, 8]
        System.out.println("Sorted list: " + numbers);

        // 3. 리스트 순서 뒤집기 (reverse)
        Collections.reverse(numbers);
        // Reversed list: [8, 5, 3, 2, 1]
        System.out.println("Reversed list: " + numbers);

        // 4. 최소값과 최대값 찾기 (min, max)
        int min = Collections.min(numbers);
        int max = Collections.max(numbers);
        // Min: 1, Max: 8
        System.out.println("Min: " + min + ", Max: " + max);

        // 5. 리스트를 무작위로 섞기 (shuffle)
        Collections.shuffle(numbers);
        // Shuffled list: [3, 8, 5, 1, 2]
        System.out.println("Shuffled list: " + numbers);

        // 6. 동기화된 리스트 생성 (synchronizedList)
        List<Integer> synchronizedList = Collections.synchronizedList(numbers);
        synchronized (synchronizedList) {
            System.out.println("Synchronized list: " + synchronizedList);
        }

        // 7. 수정 불가능한 리스트 생성 (unmodifiableList)
        List<Integer> unmodifiableList = Collections.unmodifiableList(numbers);
        System.out.println("Unmodifiable list: " + unmodifiableList);

        // 아래 코드를 실행하면 UnsupportedOperationException 발생
        // unmodifiableList.add(10);
    }
}

 
(참고)
https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-Collections-Framework-%EC%A2%85%EB%A5%98-%EC%B4%9D%EC%A0%95%EB%A6%AC

 

🧱 Java Collections Framework 종류 💯 총정리

Java Collection Framework 자바 새내기분들은 컬렉션 프레임워크라는 단어에 뭔가 거창하고 어려운 느낌이 들수 있겠지만, 그냥 자료 구조(Data Structure) 종류의 형태들을 자바 클래스로 구현한 모음집

inpa.tistory.com