Programing Language/Java

Collections Framework

JHeaon 2024. 4. 26. 20:03

 

 

오늘은 JCF(Java Collection Framework)에 대해서 정리해보고자 한다. 간단하게 말하자면 흔히 쓰는 자료구조 (스택, 큐, 링크드 리스트, 맵.... )등을 자바 클래스로 구현한 모음집이다. 

 


 

 

컬렉션 프레임워크 종류

 

 

컬렉션 프레임워크는 크게 Collection 인터페이스와 Map 인터페이스로 나뉜다. List, Set 인터페이스와 달리 Map은 두개의 데이터를 묶어 한쌍으로 다루기 때문에 Collections 인터페이스와 따로 분리되어 있다. 

 

 

 

 

Collection 인터페이스

 

- List, Set, Queue에 상속하는 최상위 컬렉션 타입

- 다양한 종류의 컬렉션을 받아 자료를 삽입하거나 삭제, 탐색 기능을 할 수 있다. 

메서드 기능
boolean add(Object o)
boolean addAll(Collection c)
객체 추가
boolean contains(Object o)
boolean conatainsAll(Collection c)
객체가 포함되어 있는지 확인
boolean remove(Object o)
boolean removeAll(Collection c)
객체 삭제
boolean retainAll(Collection c) 해당 객체를 제외한 모든 객체 삭제
void clear() 모든 객체 삭제
boolean equals(Object o) 동일한 컬렉션인지 확인
int hashCode() 해쉬 코드 반환
isEmpty() 비어있는지 확인
Iterator iterator() iterator을 얻어 반환
int size() 객체의 갯수 반환
Object[] toArray() 컬랙션에 저장된 객체를 객체 배열(Object[])로 반환
Object[] toArray(Object[] a) 지정된 배열에 컬렉션 객체를 저장해서 반환

 

 

 

 

 

List 인터페이스

- 저장 순서가 유지되는 컬렉션을 구현하는데 사용한다. 

- 같은 요소의 중복을 허용한다.

- Index을 통해 요소에 접근한다. 

- 자료형의 크기가 고정이 아닌, 동적으로 조절 할 수 있다.

메서드 설명
void add(int index, Object element)
boolean addAll(Collection c)
해당 index에 객체를 추가한다. 
Object remove(int index) 해당 인덱스에 있는 객체를 삭제한다. 
Object get(int index) 해당 인덱스에 있는 객체를 반환한다.
Object set(int index, Object element) 해당 인덱스에 객체를 저장한다. 
int indexOf(Obejct o) 객체의 위치를 반환한다. 
int lastIndexOf(Object o) 객체의 위치를 반환한다. (역으로 순회)
List subList(int formIndex, intoIndex) 지정된 범위의 객체를 반환한다. 
ListIterator listIterator()
ListIterator listIterator(int index)
List의 객체에 접근할 수 있는 ListIterator을 반환한다. 
void sort(Comparator c) 지정된 비교자로 List을 정렬한다. 

 

 

 

ArrayList 클래스

- 배열을 이용하여 만든 리스트

- 데이터의 저장순서가 유지되고 중복을 허용

- 데이터량에 따라 공간이 자동으로 늘어나거나 줄어듬

- 단방향 포인터 구조로 순차적 접근의 강점으로 조회가 빠르나 중간 삽입, 삭제가 느리다. 

 

LinkedList 클래스

- 노드를 연결하여 리스트 처럼 만든 컬렉션

- 데이터의 중간 삽입, 삭제가 빈번할 경우 빠른 선능을 보장한다. 

- 임의의 요소에 대한 접근 성능이 느리다. 

 

 

Stack 클래스

- LIFO(후입선출)의 자료구조 이다. 

- 요소를 넣을 때는 push(), 나갈때는 pop() 메소드를 이용한다. 

- Stack은 레거시 코드인 Vector을 상속하기 때문에 문제점이 많아 대신, ArrayDeque 사용을 추천하고 있다. 

 

 

 

 

Queue 인터페이스

- FIFO(선입선출)로 먼저 들어온 원소가 먼저 빠져나가는 구조이다. 

메서드 기능
boolean add(Object o) 객체 추가
Object remove() 객체 삭제
Object element() 삭제없이 요소를 읽어온다. 
boolean offer(Object o) Queue에 객체를 저장
Object poll() 객체를 꺼내서 반환한다.
Obejct peek() 삭제없이 요소를 읽어온다.

 

 

 

PriorityQueue 클래스

- 우선 순위를 가지는 큐(우선 순위 큐 라고 한다.)

- 일반적인 큐와 다르게 우선 순위를 부여하여 우선 순위가 높은 순으로 정렬되고 꺼내 진다. 

- 우선순위 큐에 저장할 객체는 반드시 Comparable 인터페이스를 구현해야 한다. compareTo() 메서드 로직에 따라 자료 객체의 우선순의를 결정하는 식으로 동작한다. 

- 저장 공간으로는 배열을 사용하고, 각 요소를 힙(Heap)형태로 저장한다. 

 

아래는 예시 코드 이다.

import java.util.*;

public class Main {

    // 우선순위 큐에 저장할 객체는 필수적으로 Comparable를 구현
    class Student implements Comparable<Student> {
        String name; // 학생 이름
        int priority; // 우선순위 값

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

        @Override
        public int compareTo(Student user) {
            // Student의 priority 필드값을 비교하여 우선순위를 결정하여 정렬
            if (this.priority < user.priority) {
                return -1;
            } else if (this.priority == user.priority) {
                return 0;
            } else {
                return 1;
            }
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", priority=" + priority +
                    '}';
        }
    }

    public void main(String[] args) {

        // 오름차순 우선순위 큐
        Queue<Student> priorityQueue = new PriorityQueue<>();

        priorityQueue.add(new Student("주몽", 5));
        priorityQueue.add(new Student("세종", 9));
        priorityQueue.add(new Student("홍길동", 1));
        priorityQueue.add(new Student("임꺽정", 2));

        // 우선순위 대로 정렬되어 있음
        System.out.println(priorityQueue);
        // [Student{name='홍길동', priority=1}, Student{name='임꺽정', priority=2}, Student{name='주몽', priority=5}, Student{name='세종', priority=9}]

        // 우선순위가 가장 높은 값을 참조
        System.out.println(priorityQueue.peek()); // Student{name='홍길동', priority=1}

        // 차례대로 꺼내기
        System.out.println(priorityQueue.poll()); // Student{name='홍길동', priority=1}
        System.out.println(priorityQueue.poll()); // Student{name='임꺽정', priority=2}
        System.out.println(priorityQueue.poll()); // Student{name='주몽', priority=5}
        System.out.println(priorityQueue.poll()); // Student{name='세종', priority=9}
    }
}

 

 

 

 

Deque 인터페이스

 

 

- Deque(Double-Ended Queue)는 양쪽으로 넣고 빼는 것이 가능한 큐를 말한다. 

- 스택 + 큐와 같은 자료구조 이며 스택으로 사용하거나 큐로 사용할 수 있다. 

- Deque의 조상은 Queue이며, 구현체로는 ArrayDeque, LinkedList가 있다. 

 

 

 

 

 

ArrayDeque클래스

 

- 스택으로 사용할때, 스택보다 빠르고 대기열로 사용할 때 LinkedList보다 빠르다.

- 사이즈에 제한이 없다. 

 

메서드 기능
offerLast(), offer(), addLast(), add() 객체를 뒤에 추가
addFirst(), offerFirst() 객체를 앞에서 추가
pollLast() 객체를 뒤에 뻄
pollFrist(), poll() 객체를 앞에서 뺌
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

 

 

LinkedList 클래스

- LinkedList는 List, Queue인터페이스를 동시에 상속받고 있기에, 스택 혹은 큐로 응용이 가능하다. 

 

 

 

 

 

Set 인터페이스

 

- 데이터의 중복을 허용하지 않고 순서를 유지하지 않는 데이터 집합 리스트

- 순서가 없어 인덱스로 객체를 가져오는 get() 함수가 존재하지 않는다.

- 중복 저장이 불가능하여 null 값 또한 하나만 저장 가능하다. 

 

메서드 설명
boolean add(E e) 객체 추가
boolean contains(Object o) 객체 저장 여부 확인
Iterator<E> iterator() iterator 반환
isEmpty() 객체가 비어있는지 확인
int Size() 저장된 객체수 반환
void clear() 모든 객체를 삭제
boolean remove(Object o) 주어진 객체를 삭제합니다. 

 

 

 

Hashset 클래스

 

- 배열과 연결 노드를 결합한 자료구조 형태

- 가장 빠른 임의 검색 접근 속도를 가진다. 

- 추가, 삭제, 검색, 접근성 모두 뛰어나다.

- 대신 순서를 예측할 수 없다. 

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 클래스

- 순서를 가지는 Set자료

- 추가된 순서 또는 가장 최근에 접근한 순서대로 접근이 가능하다.

- 중복을 제거하는 동시에 순서를 유지하고 싶다면 HashSet 대신 LinkedHashSet을 사용한다. 

Set<Integer> linkedHashSet = new LinkedHashSet<>();

linkedHashSet.add(10);
linkedHashSet.add(20);
linkedHashSet.add(30);
linkedHashSet.add(10); // 중복된 수 추가

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

linkedHashSet.toString(); // [10, 20, 30] - 대신 자료가 들어온 순서대로 출력

 

 

 

TreeSet 클래스

- 이진 검색 트리의 자료구조 형태로 데이터를 저장

- 중복을 허용하지 않고, 순서를 가지지 않음

- 대신 데이터를 정렬하고 저장하는 것이 특징

- 정렬, 검색, 범위 검색에 높은 성능을 뽑는다.

Set<Integer> treeSet = new TreeSet<>();

treeSet.add(7);
treeSet.add(4);
treeSet.add(9);
treeSet.add(1);
treeSet.add(5);

treeSet.toString(); // [1, 4, 5, 7, 9] - 자료가 알아서 정렬됨

 

 

 

 

Map 인터페이스

 

- 키와 값의 쌍으로 연관지어 이루어진 데이터의 집합

- 값은 중복되어 저장될 수 있지만, 키는 Map에서 고유해야 ㅎ한다.

- 중복된 키가 저장되면 기존 값은 없어지고 마지막에 저장된 값이 남게 된다. 

- 저장 순서가 유지되지 않는다. 

메서드 기능
void clear() 모든 객체 삭제
boolean containsKey(Object key) 지정된 객체와 key가 있는지 확인
boolean containsValue(Object key) 지정된 객체와 value가 있는지 확인
Set entrySet() Map에 저장도니 key-value쌍을 Map.Entry타입의 객체로 저장한 Set을 반환
boolean equals(Object o) 동일한 Map인지 비교
Object get(Object key) key 객체에 대응하는 value 반환
int hashCode() 해시코드 반환
boolean isEmpty() Map이 비어있는지 확인
Set keySet() Map에 저장된 모든 Key객체 반환
Collection value() Map에 저장된 모든 value값 반환
Object put(Object key, Object value) Map에 key와 value 연결하여 저장
viod putAll(Map t) 지정된 Map의 모든 key-value쌍을 추가
Object remove(Object key) 지정된 key와 일치하는 key-value객체를 삭제
int size() Map에 저장된 key-value 갯수를 반환

 

 

 

 

HashMap 클래스

- Hashtable을 보완한 컬렉션

- 배열과 연결이 결합된 Hasing 형태로, key-value을 묶어 하나의 데이터로 저장한다.

- 중복을 허용하지 않고 순서를 보장하지 않는다.

- 키와 값으로 null이 허용된다.

- 추가, 삭제, 검색, 접근이 모두 뛰어나다.

- HashMap은 비동기로 작동하기 때문에, 멀티 쓰레드 환경에서는 어울리지 않아서 이를 대체하기 위해 ConcurrentHashMap을 사용한다. 

 

Map<String, String> hashMap = new HashMap<>();

hashMap.put("love", "사랑");
hashMap.put("apple", "사과");
hashMap.put("baby", "아기");

hashMap.get("apple"); // "사과"

// hashmap의 key값들을 set 집합으로 반환하고 순회
for(String key : hashMap.keySet()) {
    System.out.println(key + " => " + hashMap.get(key));
}
/*
love => 사랑
apple => 사과
baby => 아기
*/

 

 

 

 

LinkedHashMap 클래스

- HashMap을 상속하며, Entry들이 연결 리스트를 구성하여 데이터의 순서를 보장한다. 

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

 

아래는 HashMap과 LinkedHashMap의 비교이다. 

Map<Integer, String> hashMap = new HashMap<>();

hashMap.put(10000000, "one");
hashMap.put(20000000, "two");
hashMap.put(30000000, "tree");
hashMap.put(40000000, "four");
hashMap.put(50000000, "five");

for(Integer key : hashMap.keySet()) {
    System.out.println(key + " => " + hashMap.get(key)); // HashMap 정렬 안됨
}

// ----------------------------------------------

Map<Integer, String> linkedHashMap = new LinkedHashMap<>();

linkedHashMap.put(10000000, "one");
linkedHashMap.put(20000000, "two");
linkedHashMap.put(30000000, "tree");
linkedHashMap.put(40000000, "four");
linkedHashMap.put(50000000, "five");

for(Integer key : linkedHashMap.keySet()) {
    System.out.println(key + " => " + linkedHashMap.get(key)); // LinkedHashMap 정렬됨
}

// ===============================================
20000000 => two
40000000 => four
10000000 => one
30000000 => tree
50000000 => five

10000000 => one
20000000 => two
30000000 => tree
40000000 => four
50000000 => five

 

 

 

TreeMap 클래스

- 이진 검색 트리의 형태로 키와 값의 쌍으로 이루어진 데이터를 저장한다.

- TreeMap은 SortedMap 인터페이스를 구현하고 있어 Key 값을 기준으로 정렬되는 특징을 가지고 있다. 

- 정렬된 순서로 키/값 쌍으로 저장하므로 빠른 검색(특히 범위 검색)이 가능하다.

- 정렬되는 순서는 숫자 -> 알파벳 대문자 -> 알파벳 소문자 -> 한글 순이다. 

Map<Integer, String> treeMap = new TreeMap<>();

treeMap.put(1, "Toby");
treeMap.put(2, "Ruth");
treeMap.put(3, "jennifer");
treeMap.put(4, "Mark");
treeMap.put(5, "Dan");
treeMap.put(6, "Gail");

for(Integer key : treeMap.keySet()) {
    System.out.println(key + " => " + treeMap.get(key));
}
/*
1 => Toby
2 => Ruth
3 => jennifer
4 => Mark
5 => Dan
6 => Gail
*/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

컬렉션 프레임워크 선택 시점

ArrayList

- 리스트 자료구조를 사용한다면 기본 선택

- 임의의 요소에 대한 접근성이 뛰어남

- 순차적인 추가/삭제 제일 빠름

- 요소의 추가/삭제 불리

 

LinkedList

- 요소의 추가/삭제 유리

- 임의의 요소에 대한 접근성이 좋지 않음

 

HashMap / HashSet

- 해싱을 이용해 임의의 요소에 대한 추가/삭제/검색/접근성이 모두 뛰어남

- 검색에 최고 성능 O(1)

 

TreeMap / TreeSet

- 요소 정렬이 필요할 때

- 검색에 적합

- 검색성능이 HashMap보다 떨어짐

 

LinkedHashMap / LinkedHashSet

- HashMap, HashSet에 저장 순서 유지 기능을 추가함

 

Queue / Stack

- 해당 자료구조가 필요하다면 ArrayDeque을 사용

'Programing Language > Java' 카테고리의 다른 글

Optional  (0) 2024.05.24
Stream  (0) 2024.05.09
Thread (수정중)  (1) 2024.05.01
String 객체  (0) 2024.04.30
[Java] Java가 실행되는 과정과 JDK, JRE  (0) 2023.06.23

'Programing Language/Java'의 다른글

  • 현재글 Collections Framework

관련글