자바 공부 중 Collection Framework에 대한 내용이 방대하다고 느껴져, 기억할 겸 정리한 것에 대한 기록이다. 아래 책을 공부 중이다.
신용권, 임경균, 『이것이 자바다』, 한빛미디어(2023), p120-121.
0. Collection Framework (컬렉션 프레임워크)
Collection Framework란 널리 알려진 자료구조를 바탕으로 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 만들어진 각종 인터페이스와 클래스들이다. java.util 패키지에 포함되어 있다.
Collection Framework는 크게 세 가지로 분류할 수 있는데, List, Set 그리고 Map이 이에 해당한다. List와 Set이 유사하여 이는 Collection interface로 정의되고, Map은 따로 Map interface로 정의된다. Map의 가장 큰 차이점은 List와 Set이 단일 값이 저장된 객체를 가지는 것과는 달리 Map은 key와 값으로 구성된 Entry를 저장한다는 점이다. 그리고 List와 Set을 나누는 차이는 List는 순서를 유지하고 중복 저장을 허용하지만 Set은 순서를 무시하고 중복 저장을 허용하지 않는다는 점이다.
컬렉션들은 공통적으로 아래와 같은 방식으로 생성할 수 있다. (List collection에서 ArrayList를 예로 작성되었다.)
List<E> = new ArrayList<E>(); // E에 지정된 타입의 객체만 저장
List<E> = new ArrayList<>(); // E에 지정된 타입의 객체만 저장
List list = new ArrayList(); // 모든 타입의 객체를 저장
1. List Collection (리스트 컬렉션)
List Collection은 앞서 언급했듯 순서를 지켜 객체들을 저장하는 컬렉션에 해당한다. 각 객체에 인덱스를 부여하여 검색, 삭제할 수 있는 기능을 제공한다.
List Collection에서 공통적으로 사용 가능한 List 인터페이스 메소드는 아래와 같다.
객체 추가 | boolean add(E e) | e를 맨 끝에 추가 |
void add(int index, E element) | e를 index에 추가 (index부터 하나씩 밀림) | |
set(int index, E element) | index 위치를 element로 대체 | |
객체 검색 | boolean contains(Object o) | o가 포함되어 있는지 여부 |
E get(int index) | index 위치의 객체를 리턴 | |
isEmpty() | 컬렉션이 비어있는지 여부 | |
int size() | 컬렉션 내 객체 수 | |
객체 삭제 | void clear() | 모든 객체 삭제 |
E remove(int index) | index 위치의 객체를 삭제 | |
boolean remove(Object o) | 주어진 객체 삭제 |
List Collection에는 아래와 같이 ArrayList, Vector, LinkedList 등이 있다.
Collection | 특징 | 장점 | 단점 |
ArrayList | index 0번부터 차례로 저장하여 리스트 생성 | 인덱스 별로 검색에 용이 | 삽입과 삭제가 잦을 경우 효율이 좋지 않음 |
Vector | ArrayList와 동일하지만 동기화된 메소드로 구성되어 멀티 스레드가 동시에 Vector() 메소드를 실행 불가 | 멀티 스레드 환경에서 안전하게 객체 추가/삭제 가능 (경합이 발생하지 않음) | 삽입과 삭제가 잦을 경우 효율이 좋지 않음 |
LinkedList | 인접 객체를 체인처럼 연결하여 관리 | 삽입과 삭제에 용이 | - |
2. Set Collection
Set Collection은 저장 순서를 유지하지 않고 객체들을 저장하는 컬렉션에 해당한다. 객체를 중복해서 저장할 수는 없다. 따라서 수학의 집합에 비유될 수 있다. 따라서 객체의 hashCode() 메소드 리턴값이 같고, equals() 메소드가 true를 리턴하면 동일한 객체라고 판단하고 중복 저장하지 않는다.
Set Collection에서 공통적으로 사용 가능한 List 인터페이스 메소드는 아래와 같다. 인덱스로 관리하지 않기 때문에 인덱스를 매개값으로 갖는 메소드는 없다.
객체 추가 | boolean add(E e) | e를 맨 끝에 추가 (성공 시 true, 실패 시 false 리턴) |
객체 검색 | boolean contains(Object o) | o가 포함되어 있는지 여부 |
isEmpty() | 컬렉션이 비어있는지 여부 | |
Iterator<E> iterator() | 저장된 객체를 한 번씩 가져오는 반복자 리턴 | |
int size() | 컬렉션 내 객체 수 | |
객체 삭제 | void clear() | 모든 객체 삭제 |
boolean remove(Object o) | 주어진 객체 삭제 |
Set Collection에는 HashSet, LinkedHashSet, TreeSet 등이 있다.
여기서 Set Collection은 index가 없기 때문에 iterator(반복자)를 사용하는데, 이는 다음 메소드를 제공한다. 아래의 hasNext() 메소드를 통해 남은 객체가 있는지 확인을 하면서, next() 메소드로 하나씩 객체를 가져오는 식으로 순회할 수 있다.
boolean hasNext() | 남은 가져올 객체가 있는지 여부 |
E next() | Collection에서 하나의 객체를 가져옴 |
void remove() | next()로 가져온 객체를 Set Collection에서 제거 |
3. Map Collection
Map Collection은 key와 value로 구성된 entry 객체를 저장하는 형태이다. 여기서 key만 중복 저장이 불가능하다. value가 같더라도 key가 다르면 각각 저장이 가능하다. 만약 같은 key값이 한 번 더 추가되면, 새로운 값으로 대체된다.
Map Collection에서 공통적으로 사용 가능한 List 인터페이스 메소드는 아래와 같다.
객체 추가 | V put(K key, V value) | 주어진 key와 value를 추가하고 저장되면 value 리턴 |
객체 검색 |
boolean containsKey(Object key) | 주어진 key가 포함되어 있는지 여부 |
boolean containsValue(Object value) | 주어진 value가 포함되어 있는지 여부 | |
Set<Map.Entry<K, V>> entrySet() | key와 value의 쌍으로 구성된 모든 Map.Entry 객체를 Set에 담아 리턴 | |
V get(Object key) | 주어진 key값을 가진 value를 리턴 | |
boolean isEmpty() | Collection이 비어있는지 여부 | |
Set<K> keySet() | 모든 key 객체를 담은 Set을 리턴 | |
int size() | 저장된 키의 수를 리턴 | |
Collection<V> values() | 모든 value 객체를 담은 Collection을 리턴 | |
객체 삭제 | void clear() | 모든 Map.Entry를 삭제 |
V remove(Object key) | 주어진 key를 가진 Entry를 삭제 |
Map Collection에는 아래와 같이 HashMap, Hashtable, LinkedHashMap, Properties, TreeMap 등이 있다.
Collection | 특징 |
HashMap | key로 사용할 객체의 hashCode() 메소드 리턴값이 같고 equals() 리턴값이 true인 경우 중복 저장을 허용하지 않음 (즉, 키 값의 중복을 허용하지 않음) |
Hashtable | HashMap과 동일하지만 synchronized method로 구성되어 멀티 스레드가 동시에 Hashtable 메소드들을 실행할 수 없음 (즉, 경합이 발생하지 않아 안전하게 객체를 추가, 삭제 가능) |
Properties | Hashtable의 자식 객체이지만 key와 value를 String type으로 제한 (확장자가 .properties인 프로퍼티 파일을 읽을 때 주로 사용) |
(+) 검색 기능을 강화한 Binary Tree Collection
Collection Framework는 검색 기능을 강화한 TreeSet과 TreeMap을 제공한다. 이 두 컬렉션은 이진 트리(binary tree)를 기반으로 한 컬렉션들로, 여러 개의 노드(node)가 트리 형태로 연결되어 있다. 루트노드(root node)로 시작하여 각 노드가 최대 2개의 자식 노드를 가지는데, 각각 left node, right node를 가지는 것이다.
이 타입의 collection을 생성할 때는 보통의 collection에서와는 다르게 Set이나 Map 타입 변수에 대입하지 않고, TreeSet과 TreeMap 타입 변수에 대입하는 편이 낫다. 왜냐하면 TreeSet과 TreeMap 타입만이 가지는 검색 관련 메소드들이 있기 때문이다.
TreeSet의 경우는 노드가 하나의 객체로 구성된다. TreeSet은 저장과 동시에 객체를 기준으로 오름차순으로 정렬된다. 부모 객체와 비교해서 낮은 것은 왼쪽, 높은 것은 오른쪽 자식 노드에 저장되는 방식이다. TreeSet이 가진 검색 관련 메소드들은 다음과 같다.
특정 객체 가져오기 |
E first() | 제일 낮은 객체를 리턴 (오름차순에서 첫번째 객체) |
E last() | 제일 높은 객체를 리턴 (오름차순에서 마지막 객체) | |
E lower(E e) | 주어진 객체보다 바로 아래 객체를 리턴 (오름차순에서 주어진 객체보다 바로 앞순서 객체) | |
E highr(E e) | 주어진 객체보다 바로 위 객체를 리턴 (오름차순에서 주어진 객체보다 바로 뒷순서 객체) | |
E floor(E e) | 주어진 객체와 같거나 낮은 객체 하나 리턴 | |
E ceiling(E e) | 주어진 객체와 같거나 높은 객체 하나 리턴 | |
E pollFirst() | 제일 낮은 객체를 리턴하고 삭제 | |
E pollLast() | 제일 높은 객체를 리턴하고 삭제 | |
내림차순 정렬하기 |
Iterator<E> descendingIterator() | 내림차순으로 정렬된 Iterator 리턴 |
NavigableSet<E> descendingSet | 내림차순으로 정렬된 NavigableSet을리턴 | |
특정 range set 가져오기 |
NavigableSet<E> headSet(E toElement, boolean inclusive) | toElement보다 낮은 객체들을 NavigableSet으로 리턴 (inclusive가 true일 때 toElement 포함) |
NavigableSet<E> tailSet(E fromElement, boolean inclusive) | fromElement보다 높은 객체들을 NavigableSet으로 리턴 (Inclusive가 true일 때 fromElement 포함) |
|
NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) |
from Element와 toElement 사이에 있는 객체들을 NavigableSet으로 리턴 |
TreeMap은 노드가 key와 value로 구성된 Entry이다. TreeMap은 key를 기준으로 정렬된다. 부모 노드의 key와 비교해서 낮은 것은 왼쪽, 높은 것은 오른쪽 자식 노드에 Entry 객체를 저장한다. TreeMap이 가진 검색 관련 메소드들은 다음과 같다.
특정 Entry 가져오기 |
Map.Entry<K, V> firstEntry() | 제일 낮은 Map.Entry를 리턴 (오름차순에서 첫번째 객체) |
Map.Entry<K, V> lastEntry() | 제일 높은 Map.Entry를 리턴 (오름차순에서 마지막 객체) | |
Map.Entry<K, V> lowerEntry(K key) | 주어진 key보다 바로 아래 Map.Entry를 리턴 (오름차순에서 주어진 객체보다 바로 앞순서 객체) |
|
Map.Entry<K, V> highrEntry(K k) | 주어진 key보다 바로 위 Map.Entry를 리턴 (오름차순에서 주어진 객체보다 바로 뒷순서 객체) |
|
Map.Entry<K, V> floorEntry(K key) | 주어진 key와 같거나 낮은 Map.Entry 하나 리턴 | |
Map.Entry<K, V> ceilingEntry(K key) | 주어진 key와 같거나 높은 Map.Entry 하나 리턴 | |
Map.Entry<K, V> pollFirstEntry() | 제일 낮은 Map.Entry를 리턴하고 삭제 | |
Map.Entry<K, V> pollLastEntry() | 제일 높은 Map.Entry를 리턴하고 삭제 | |
내림차순 정렬하기 |
Iterator<K> descendingKeySet() | 내림차순으로 정렬된 key의 Iterator 리턴 |
NavigableMap<K, V> descendingMap() | 내림차순으로 정렬된 Map.Entry의 NavigableSet을 리턴 | |
특정 range set 가져오기 |
NavigableMap<K, V> headMap(K toKey, boolean inclusive) |
toKey보다 낮은 Map.Entry들을 NavigableMap으로 리턴 (inclusive가 true일 때 toKey를 가진 Map.Entry 포함) |
NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) | fromKey보다 높은 Map.Entry들을 NavigableMap으로 리턴 (Inclusive가 true일 때 fromKey를 가진 Map.Entry 포함) |
|
NavigableMap<K, V> subSet(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) |
fromKey와 toKey사이에 있는 MapEntry들을 NavigableMap으로 리턴 |
위와 같이 TreeSet과 TreeMap은 저장과 동시에 오름차순으로 정렬하기 때문에, 저장되는 객체들이 Comparable 인터페이스를 구현하고 있어야 한다. 즉, 비교 가능한 객체여야 한다. 만약 비교 가능한 객체가 아닌 경우에는 Comparable 인터페이스를 구현하여 CompareTo() 메소드를 Override하면 된다. 만약 Comaprable 비구현 객체를 저장하고 싶다면 TreeSet이나 TreeMap 생성 시에 비교자(Comparator 인터페이스를 구현한 객체)를 제공하면 된다.
'개발 언어 및 알고리즘 기초 > JAVA 기초' 카테고리의 다른 글
[Java] 스트림(Stream) 요소 처리 (0) | 2024.04.25 |
---|---|
[Java] Wrapper Class (래퍼 클래스, 포장 클래스) (0) | 2024.04.18 |
[JAVA] StringBuilder로 문자열 조작하기 (0) | 2024.04.17 |
[JAVA] Thread 상태 (0) | 2024.04.10 |
[JAVA / 비트 논리 연산자] 비트 논리 연산자의 필요성 증명 과정 이해하기 (0) | 2024.03.04 |