Java Collection Framework

2023. 4. 19. 17:17Spring/Java

Collection Framework

자바는 여러 객체를 그룹으로 만들고 추가, 삭제, 검색 등의 조작을 효율적으로 사용할 수 있는 interface와 class 들을 java.util 패키지에서 제공한다. 이들을 총칭해서 Collection Framework라고 한다.

 

Collection Framework의 구조

Collection Framework 에는 크게 List, Set, Map이 있다. Map의 경우 Collection interface를 상속하지는 않지만 그래도 Collection Framework으로 분류된다.

 

위의 그림에서 초록색 박스는 Interface, 주황색 박스는 Class이다. 물론 그림에 있는 게 다는 아니지만 많이 사용하는 것 위주로 적어보았다. 이 글에서는 대략적인 특징만 설명하고 구체적인 내용은 각각의 포스트를 만들어 작성할 예정이다.

 

 

1. List Interface

순서가 있는 객체들의 집합으로 중복을 허용한다. 자바의 배열과 비슷하다. 하지만 배열과는 다르게 저장 용량이 자동으로 증가하며 (동적), 객체를 저장할 때 자동으로 인덱스가 부여된다. 또한 조작을 효율적으로 할 수 있게 해주는 여러 가지 메소드를 제공한다.

 

List는 내부에 객체 자체를 저장하는 것이 아니라 객체의 주소를 참조한다. 이에 동일한 객체를 중복 저장할 경우 동일한 주소를 참조하는 것이다.

 

  • ArrayList : List interface의 대표적인 구현체 (class)이다. 
    1. Dynamic Resizing (동적 크기 조절) : 저장 용량을 초과하면 자동으로 두 배의 저장 용량을 가진다.
    2. Random Access (임의 접근) : 인덱스에 따라 빠르게 요소에 직접 접근할 수 있다.
    3. Ordered elements (정렬 저장) : 요소가 추가될 때 순서를 유지한다.
    4. Duplicate elements (중복 저장) : 중복 저장이 가능하다.
    5. Null elements (null 값 가능) : Null 값을 저장할 수 있다. (이 경우 객체 주소를 참조하지 않는다.)

  • Stack : LIFO(Last In First Out)의 특징을 가지는 stack 자료구조의 구현체이다.
    1. LIFO (후입선출) : 마지막으로 추가된 요소가 가장 먼저 제거된다.

  • Vector : ArrayList와 비슷하지만 Synchronized 메소드로 구성되어 있다.
    1. Synchronized : 동기화된 메소드로 구성되어 있어서 Multi-Thread 환경에서 더 안전하다.
    2. Deprecated : 더 이상 사용되지 않는다. (Java 5부터 ConCurrentHashMap, CopyonWriteArrayList 등의 더 나은 성능을 가진 것들이 쓰인다.)

  • LinkedList : Doubly LinkedList로 만들어져 있는 linkedList 자료구조의 구현체이다.
    1. Memory Overhead : 하나의 Node가 두 개의 참조를 저장해야 되기 때문에 ArrayList보다 메모리 사용량이 많다. 끝에서부터 추가 또는 삭제하는 경우는 ArrayList가 빠르지만, 중간에 추가, 삭제 하는 경우는 LinkedList가 더 빠르다. ArrayList는 변경된 이후 뒤의 index를 모두 바꿔줘야 하기 때문에 O(n)이 더 붙는다. 하지만 검색만 하는 경우는 ArrayList가 훨씬 빠르다.

구분 순차적으로 추가 / 삭제 중간에 추가 / 삭제 검색
ArrayList 빠르다 느리다 빠르다
LinkedList 느리다 빠르다 느리다

 

2. Set Interface

List Interface와 반대로 객체들의 순서가 없는 객체들의 집합이고 중복도 허용하지 않는다. 수학에서 "집합"과 같은 개념이다. 이에 인덱스 개념이 적용되지 않기 때문에 인덱스를 parameter로 갖는 메소드가 없다.

 

  • HashSet : Set Interface의 대표적인 구현체이다
    1. Fast Random Access : 내부적으로 HashTable을 사용하기 때문에 O(1)의 시간복잡도의 조작이 가능하다.
    2. Unique elements : 객체들이 중복되지 않는다.
    3. Unordered elements : 객체들의 순서가 보장되지 않는다.

  • TreeSet : 기본적으로 정렬되어 있으며 정렬방법을 지정할 수 있다.
    1. 정렬 작업이 필요 없는 경우 HashSet을 이용하는 것이 낫다.

 

3. Map Interface

key 객체, value 객체의 한 쌍으로 이루어진 Map.Entry 객체들의 집합이다. key는 중복 불가하지만 value는 중복 가능하다. python dictionary와 비슷하다. 

 

  • HashMap : Map Interface의 대표적인 구현체이다.
    1. 동기화되지 않으므로 Multi-Thread 환경에서 이용할 때에는 ConcurrentHashMap을 이용해야 한다.

  • HashTable : HashMap과 동일한 내부구조를 가지지만 동기화를 지원한다.
    1. 동기화를 지원하며 동시에 많은 작업이 필요한 경우 ConcurrentHashMap을 쓰는 게 좋지만 안정성만 필요하다면 HashTable을 쓰는게 나을 수도 있다. ConcurrentHashMap 보다 간단하고 사용하기 쉽기 때문이다.

  • TreeMap : 정렬된 순서대로 key, value를 저장한다.
    1. 빠른 검색 : 정렬된 순서대로 저장하기 때문에 객체에 접근이 더 빠르다.
    2. 정렬을 유지할 필요가 없다면 메모리를 덜 사용하고 더 빠른 HashMap을 사용하는 편이 낫다.