본문 바로가기

Java

Java Collections Framework


Set

Set 인터페이스의 구현체들은 내부적으로 Map 인터페이스의 구현체들을 사용한다.

HashSet은 내부적으로 HashMap을 사용하고 TreeSet은 TreeMap, LinkedHashSet은 LinkedHashMap을 사용한다. Map인터페이스의 key만 사용하고 value는 항상 같은 Dummy값을 넣어두고 사용하지 않는다.

이러한 특징은 Set 인터페이스에 get() 메서드가 없는 것과도 관련 있는데 Map 인터페이스 자체에는 getKey() 메서드가 없다. 그러므로 Set에서도 get() 메서드를 사용하는게 구조적으로 불가능한 것이다.

사실 Set은 순서와 상관없이 중복되지 않는 데이터를 저장할 목적으로 만들어지고 여러 데이터를 넣어두고 해당 데이터가 존재하는지 확인하는 용도로 많이 사용한기 때문에 get() 메서드는 Set의 존재 목적과도 맞지 않다. Set 인터페이스를 목적에 맞게 잘 활용하고 있다면 get() 메서드의 필요성을 느끼지 못할 수도 있다.

  • HashSet: 데이터를 해쉬 테이블에 담는 클래스로 순서 없이 저장된다.
  • TreeSet: red-black 트리에 데이터를 담는다. 값에 따라서 순서가 정해진다. 데이터를 담으면서 동시에 정렬을 하기 때문에 HashSet보다 성능상 느리다.
  • LinkedHashSet: 해쉬 테이블에 데이터를 담는데, 저장된 순서에 따라서 순서가 결정된다.

red-black 트리는 자료의 삽입과 삭제, 검색에서 최악의 경우에도 일정한 실행 시간을 보장한다. 이는 실시간 처리와 같은 실행시간이 중요한 경우에 유용하게 쓰일 뿐만 아니라, 일정한 실행 시간을 보장하는 또 다른 자료구조를 만드는 데에도 쓸모가 있다. 예를 들면, 각종 기하학 계산에 쓰이는 많은 자료 구조들이 레드-블랙 트리를 기반으로 만들어져 있다.


List

  • Vector: ArrayList와 비슷하지만 동기화가 되어있고 크기를 100% 증가시키는 차이가 있는 동적 배열
  • ArrayList: 동기화 처리가 되어있지 않고 크기를 50% 증가시킨다.
  • LinkedList: Queue 인터페이스를 구현했기 때문에 FIFO 큐 작업을 수행

Map

Map 인터페이스와 이 구현체들은 Collection에 속하지만 Map은 컬렉션이 아니다.

왜 Map은 Collection 인터페이스를 상속하지 않는가?

'엘리먼트들의 그룹'이라는 컬렉션 인터페이스의 기본 개념과 맞지 않음.

처음 데이터를 구분할 때 Set, List, Map으로 구분했고 Set과 List는 공통된 부분이 많아서 따로 추출한 인터페이스가 Collection 인터페이스이다. Map은 Key와 Value의 쌍으로 저장되는 구조체이기에 자료구조상 맞지 않는 부분이 많았다. 그래서 Collection에 추가를 하지 않았다.

  • Hashtable: 데이터를 해쉬 테이블에 담는 클래스, 내부에서 관리하는 해쉬 테이블 객체가 동기화되어 있으므로, 동기화가 필요한 부분에서는 이 클래스를 사용하자.
  • HashMap: 데이터를 해쉬 테이블에 담는 클래스, Hashtable과 다른 점은 null값을 허용한다는 점과 동기화되어 있지 않다는 점이다.
  • TreeMap: red-black 트리에 데이터를 담는다. TreeSet과 다른 점은 키에 의해서 순서가 정해진다는 것이다. TreeSet도 TreeMap의 key만 사용하기에 내부적으로는 같은 것이다.
  • LinkedHashMap: HashMap과 거의 동일하며 이중 연결 리스트라는 방식을 사용하여 데이터를 담는다.

Queue

Queue 인터페이스를 구현한 클래스는 두가지로 나뉜다. util 패키지에 속하는 LinkedList와 PriorityQueue는 일반적인 목적의 큐 클래스이고 concurrent 패키지에 속하는 클래스들은 스레드에 안전한 컨커런트 큐 클래스이다.

  • LinkedBlockingQueue: 저장할 데이터의 크기를 선택적으로 정할수도 있는 FIFO 기반의 링크 노드를 사용하는 블로킹 큐
  • ArrayBlockingQueue: 저장되는 데이터의 크기가 정해져 있는 FIFO 기반의 블로킹 큐
  • PriorityBlockingQueue: 저장되는 데이터의 크기가 정해져 있지 않고 객체의 생성순서에 따라서 순서가 저장되는 블로킹 큐
  • DelayQueue: 큐가 대기하는 시간을 지정하여 처리하도록 되어 있는 큐
  • SynchronousQueue: put() 메서드를 호출하면, 다른 스레드에서 take() 메서드를 호출될 때까지 대기하도록 되어 있는 큐, 이 큐에는 저장되는 데이터가 없다. API에서 제공하는 대부분의 메서드는 0이나 null을 리턴한다.

blocking queue란 크기가 지정되어 있는 큐에 더 이상 공간이 없을 때, 공간이 생길 때 까지 대기하도록 만들어진 큐를 의미한다.


참고 자료