IT 개발노트
컬렉션이란 본문
1. 컬렉션(Collections)
1.1 컬렉션이란?
: 컬렉션이란 우리말로 쉽게 말해서 자료구조이다. 더 쉽게 말하면 배열이다.
1.2 자료구조
1.3 컬렉션의 핵심 인터페이스와 특징
인터페이스 |
특징 |
List |
순서가 있는 데이터의 집합, 데이터의 중복을 허용한다. |
구현클래스 : ArrayList, LinkedList, Stack, Vector 등 |
|
Set |
순서를 유지하지 않는 데이터의 집합, 데이터의 중복을 허용하지 않는다. |
구현클래스 : HashSet, TreeSet 등 |
|
Map |
키(key)와 값(value)의 쌍(pair)으로 이루어진 데이터의 집합 |
구현클래스 : HashMap, TreeMap, Hashtable, Properties 등 |
1.4 List계열 컬렉션 클래스
: List는 배열과 비슷하지만, 배열의 단점을 보완 하였다. List인터페이스는 중복을 허용하면서 저장순서가 유지되는 컬렉션을 구현하는데 사용된다.
List는 처음 만들 때 크기를 고정하지 않아도 된다.
1.4.1 ArrayList
: ArrayList는 배열과 매우 비슷하다. 인덱스가 존재하며, 데이터는 중복되어도 상관 없다.(인덱스가 가장 중요하다)
ArrayList를 생성할 때, 저장할 요소의 개수를 고려해서 실제 저장할 개수보다 약간 여유있는 크기로 하는 것이 좋다. 생성할 때 지정한 크기보다 더 많은 객체를 저장하면 자동적으로 크기가 늘어나기는 하지만 이 과정에서 처리시간이 많이 소요되기 때문이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package sungju.Java.Test2; import java.util.ArrayList; public class Test2 { public static void main(String[] args) { ArrayList<String> arrayList = new ArrayList<String>(); arrayList.add("str0"); arrayList.add("str1"); arrayList.add("str2"); arrayList.add("str3"); System.out.println(arrayList.toString()); arrayList.set(2, "str222222"); System.out.println(arrayList.toString()); arrayList.remove(2); System.out.println(arrayList.toString()); System.out.println(arrayList.size()); arrayList.clear(); System.out.println(arrayList.toString()); arrayList = null; System.out.println(arrayList); System.out.println(arrayList.toString()); } } |
메서드 |
설명 |
ArrayList() |
크기가 10인 ArrayList를 생성 |
ArrayList(Collection c) |
주어진 컬렉션이 저장된 ArrayList를 생성 |
ArrayList(int initialCapacity) |
지정된 초기용량을 갖는 ArrayList를 생성 |
boolean add(Object o) |
ArrayList의 마지막에 객체를 추가, 성공하면 true |
void add(int index, Object element) |
지정된 위치(index)에 객체를 저장 |
boolean addAll(Collection c) |
주어진 컬렉션의 모든 객체를 저장한다. |
boolean addAll(int index, Collection c) |
지정된 위치부터 주어진 컬렉션의 모든 객체를 저장한다. |
void clear() |
ArrayList를 완전히 비운다. |
Object clone() |
ArrayList를 복제한다. |
boolean contains(Object o) |
지정된 객체(o)가 ArrayList에 포함되어 있는지 확인 |
void ensureCapacity(int minCapacity) |
ArrayList의 용량이 최소한 minCapacity가 되도록 한다. |
Object get(index) |
지정된 위치(index)에 저장된 객체를 반환한다. |
int indexOf(Object o) |
지정된 객체가 저장된 위치를 찾아 반환한다. |
boolean isEmpty() |
ArrayList가 비어있는지 확인한다. |
Iterator iterator() |
ArrayList의 Iterator객체를 반환 |
int lastIndexOf(Object o) |
객체(o)가 저장된 위치를 끝부터 역방향으로 검색해서 반환 |
ListIterator listIterator() |
ArrayList의 ListIterator를 반환 |
ListIterator listIterator(int index) |
ArrayList의 지정된 위치부터 시작하는 ListIterator를 반환 |
Object remove(int index) |
지정된 위치(index)에 있는 객체를 제거한다. |
boolean remove(Object o) |
지정한 객체를 제거한다.(성공하면 true, 실패하면 false) |
boolean romoveAll(Collection c) |
지정한 컬렉션에 저장된 것과 동일한 객체들을 ArrayList에서 제거한다. |
boolean retainAll(Collection c) |
ArrayList에 저장된 객체 중에서 주어진 컬렉션과 공통된 것들만을 남기고 나머지는 삭제한다. |
Object set(int index, Object element) |
주어진 객체(element)를 지정된 위치(index)에 저장한다. |
int size() |
ArrayList에 저장된 객체의 개수를 반환한다. |
void sort(Comparator c) |
지정된 정렬기준(c)으로 ArrayList를 정렬 |
List subList(int fromIndex, int toIndex) |
fromIndex부터 toIndex사이에 저장된 객체를 반환한다. |
Object[] toArray() |
ArrayList에 저장된 모든 객체들을 객체배열로 반환한다. |
Object[] toArray(Object[] a) |
ArrayList에 저장된 모든 객체들을 객체배열 a에 담아 반환한다. |
void trimToSize() |
용량을 크기에 맞게 줄인다.(빈 공간을 없앤다.) |
1.4.2 LinkedList
: 불연속적으로 존재하는 데이터를 서로 연결(link)한 형태이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package sungju.Java.Test2; import java.util.LinkedList; public class Test2 { public static void main(String[] args) { LinkedList<String> linkedList = new LinkedList<String>(); linkedList.add("str0"); linkedList.add("str1"); linkedList.add("str2"); linkedList.add("str3"); System.out.println(linkedList.toString()); linkedList.add("str4"); System.out.println(linkedList.toString()); linkedList.add(2, "STR2"); System.out.println(linkedList.toString()); linkedList.set(2, "str222222"); System.out.println(linkedList.toString()); linkedList.remove(2); System.out.println(linkedList.toString()); System.out.println(linkedList.size()); linkedList.clear(); System.out.println(linkedList.toString()); linkedList = null; System.out.println(linkedList); System.out.println(linkedList.toString()); } } |
- ArrayList는 인덱스 끝번호로 추가, LinkedList는 인덱스 번호를 입력해주면 그 이후 인덱스들이 한자리씩 밀린다.
1.4.3 ArrayList와 LinkedList의 비교
컬렉션 |
읽기(접근시간) |
추가 / 삭제 |
비고 |
ArrayList |
빠르다 |
느리다 |
순차적인 추가 삭제는 더 빠름 |
LinkedList |
느리다 |
빠르다 |
데이터가 많을수록 접근성이 떨어짐 |
- 순차적으로 추가/삭제하는 경우에는 ArrayList가 빠르다.
- 중간 데이터를 추가/삭제하는 경우 LinkedList가 빠르다.
1.5 Map계열 컬렉션 클래스
: Map인터페이스는 키(key)와 값(value)을 하나의 쌍으로 묶어서 저장하는 컬렉션 클래스를 구현하는데 사용된다. 키는 중복될 수 없지만 값은 중복을 허용한다.
기존에 저장된 데이터와 중복된 키와 값을 저장하면 기존의 값은 없어지고 마지막에 저장된 값이 남는다.
- 참고 : HashMap은 순서가 없지만, LinkedHashMap은 저장한 순서대로 출력이된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package sungju.Java.Test2; import java.util.HashMap; import java.util.Iterator; public class Test2 { public static void main(String[] args) { HashMap<Integer, String> hashMap = new HashMap<Integer, String>(); hashMap.put(0, "str0"); hashMap.put(1, "str1"); hashMap.put(2, "str2"); hashMap.put(3, "str3"); System.out.println(hashMap.toString()); hashMap.remove(2); System.out.println(hashMap.toString()); hashMap.clear(); System.out.println(hashMap.toString()); hashMap.put(0, "str0"); hashMap.put(1, "str1"); hashMap.put(2, "str2"); hashMap.put(3, "str3"); System.out.println(hashMap.toString()); Iterator <Integer> iterator = hashMap.keySet().iterator(); while (iterator.hasNext()) { System.out.println(hashMap.get(iterator.next())); } } } |
1.5.1 Map인터페이스의 메서드
메서드 |
설명 |
void clear() |
Map의 모든 객체를 삭제한다. |
boolean containsKey(Object key) |
지정된 key객체와 일치하는 Map의 key객체가 있는지 확인한다. |
boolean containsValue(Object value) |
지정된 value객체와 일치하는 Map의 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객체를 반환한다. |
Object put(Object key, Object value) |
Map에 value객체를 key객체에 연결(mapping)하여 저장한다. |
void putAll(Map t) |
지정된 Map의 모든 key-value쌍을 추가한다. |
Object remove(Object key) |
지정한 Key객체와 일치하는 key-value객체를 삭제한다. |
int size() |
Map에 저장된 key-value쌍의 개수를 반환한다. |
Collection values() |
Map에 저장된 모든 value객체를 반환한다. |
1.5.2 HashMap의 생성자와 메서드
생성자 / 메서드 |
설명 |
HashMap() |
HashMap객체를 생성 |
HashMap(int initialCapacity) |
지정된 값을 초기용량으로 하는 HashMap객체를 생성 |
HashMap(int initialCapacity, float loadFactor) |
지정된 초기용량과 load factor의 HashMap객체를 생성 |
HashMap(Map m) |
지정된 Map의 모든 요소를 포함하는 HashMap을 생성 |
void clear() |
HashMap에 저장된 모든 객체를 제거 |
Object clone() |
현재 HashMap을 복제해서 반환 |
boolean containsKey(Object key) |
HashMap에 지정된 키(key)가 포함되어있는지 알려준다. (포함되어 있으면 true) |
boolean containsValue(Object value) |
HashMap에 지정된 값(value)이 포함되어있는지 알려준다. (포함되어 있으면 true) |
Set entrySet() |
HashMap에 저장된 키와 값을 엔트리(키와 값의 결합)의 형태로 Set에 저장해서 반환 |
Object get(Object key) |
지정된 키(key)의 값(객체)을 반환, 못찾으면 null 반환 |
Object getOrDefalt(Object key, Object defaultValue) |
지정된 키 (key)와 값(객체)을 반환한다. 키를 못찾으면, 기본값 (defaultValue)로 지정된 객체를 반환 |
boolean isEmpty() |
HashMap이 비어있는지 알려준다. |
Set keySet() |
HashMap에 저장된 모든 키가 저장된 Set을 반환 |
Object put(Object key, Object value) |
지정된 키와 값을 HashMap에 저장 |
void putAll(Map m) |
Map에 저장된 모든 요소를 HashMap에 저장 |
Object remove(Object key) |
HashMap에서 지정된 키로 저장된 값(객체)를 제거 |
Object replace(Object key, Object value) |
지정된 키의 값을 지정된 객체(value)로 대체 |
boolean replace(Object key, Object oldValue, Object newValue) |
지정된 키와 객체(oldValue)가 모두 일치하는 경우에만 새로운 객체(new Value)로 대체 |
int size() |
HashMap에 저장된 요소의 개수를 반환 |
Collection values() |
HashMap에 저장된 모든 값을 컬렉션의 형태로 반환 |
1.5.3 Map.Entry
: Map.Entry인터페이스는 Map인터페이스의 내부 인터페이스이다. 내부 클래스와 같이 인터페이스도 인터페이스 안에 인터페이스를 정의하는 내부 인터페이스(inner interface)를 정의하는 것이 가능하다.
Map에 저장되는 key-value쌍을 다루기 위해 내부적으로 Entry인터페이스를 정의해 놓았다.
Map인터페이스를 구현하는 클래스에서는 Map.Entry인터페이스도 함께 구현해야한다.
1.6 Set계열 컬렉션 클래스
: Set인터페이스는 중복을 허용하지 않고 저장순서가 유지되지 않는 컬렉션 클래스를 구현하는데 사용된다.
1.6.1 HashSet
: HashSet은 Set인터페이스를 구현한 가장 대표적인 컬렉션이며, Set인터페이스의 특징대로 HashSet은 중복된 요소를 저장하지 않는다.
HashSet에 새로운 요소를 추가할 때는 add메서드나 addAll메서드를 사용하는데, 만일 HashSet에 이미 저장되어 있는 요소와 중복된 요소를 추가하고자 한다면 이 메서드들은 false를 반환함으로써 중복된 요소이기 때문에 추가에 실패했다는 것을 알린다.
1.7 Stack과 Queue
: 스택은 마지막에 저장한 데이터를 가장 먼저 꺼내게 되는 LIFO(Last In First Out)구조로 되어 있고,
큐는 처음에 저장한 데이터를 가장 먼저 꺼내게 되는 FIFO(Fist In First Out)구조로 되어 있다.
- 순차적으로 데이터를 추가하고 삭제하는 스택에는 ArrayList와 같은 배열기반의 컬렉션이 적합하다.
- 큐는 ArrayList보다 데이터의 추가/삭제가 쉬운 LinkedList로 구현하는 것이 적합하다.
1.7.1 Stack의 메서드
메서드 |
설명 |
boolean empty() |
Stack이 비어있는지 알려준다. |
Object peek() |
Stack의 맨 위에 저장된 객체를 반환. pop()과 달리 Stack에서 객체를 꺼내지는 않음. (비었을 때는 EmptyStackException발생) |
Object pop() |
Stack의 맨 위에 저장된 객체를 꺼낸다. (비었을 때는 EmptyStack Exception 발생) |
Object push(Object item) |
Stack에 객체(item)를 저장한다. |
int search(Object o) |
Stack에서 주어진 객체(o)를 찾아서 그 위치를 반환. 못 찾으면 -1을 반환(배열과 달리 위치는 0이 아닌 1부터 시작) |
1.7.2 Queue의 메서드
메서드 |
설명 |
boolean add(Object o) |
지정된 객체를 Queue에 추가한다. 성공하면 true를 반환. 저장공간이 부족하면 IllegalStateException발생 |
Object remove() |
Queue에서 객체를 꺼내 반환. 비어있으면 NoSuchElementException발생 |
Object element() |
삭제없이 요소를 읽어온다. peek와 달리 Queue가 비었을 때 NoSuchElementException발생 |
boolean offer(Object o) |
Queue에 객체를 저장. 성공하면 true, 실패하면 false를 반환 |
Object poll() |
Queue에서 객체를 꺼내서 반환, 비어있으면 null을 반환 |
Object peek() |
삭제없이 요소를 읽어 온다. Queue가 비어있으면 null을 반환 |
1.7.3 스택과 큐의 활용
- 스택의 활용 예 : 수식계산, 수식괄호검사, 워드프로세서의 undo/redo, 웹 브라우저의 뒤로/앞으로
- 큐의 활용 예 : 최근사용문서, 인쇄작업 대기목록, 버퍼(buffer)
1.8 Iterator, ListIterator, Enumeration
: Iterator, ListIterator, Enumeration은 모두 컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스이다.
Enumeration은 Iterator의 구버젼이며, ListIterator는 Iterator의 기능을 향상 시킨 것이다.
1.8.1 Iterator
: Iterator는 컬렉션에 저장된 각 요소에 접근하는 기능을 가진 Iterator인터페이스를 정의하고, Collection인터페이스에는 'Iterator(Iterator를 구현한 클래스의 인스턴스)'를 반환하는 iterator()를 정의하고 있다.
1.8.2 Iterator인터페이스의 메서드
메서드 |
설명 |
boolean hasNext() |
읽어 올 요소가 남아있는지 확인한다. 있으면 true, 없으면 false를 반환한다. |
Object next() |
다음 요소를 읽어 온다. next()를 호출하기 전에 hasNext()를 호출해서 읽어 올 요소가 있는지 확인하는 것이 안전하다. |
void remove() |
next()로 읽어 온 요소를 삭제한다. next()를 호출한 다음에 remove()를 호출해야한다.(선택적 기능) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package sungju.Java.Test3; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Test3 { public static void main(String[] args) { List list = new ArrayList(); // 다른 컬렉션으로 변경할 때는 이 부분만 고치면 된다. Iterator it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } } |
- 참조변수의 타입을 ArrayList타입이 아니라 List타입으로 한 이유는 ?
: List에 없고 ArrayList에만 있는 메서드를 사용하는게 아니라면, List타입의 참조변수로 선언하는 것이 좋다.
만일 List인터페이스를 구현한 다른 클래스, 예를들면 LinkedList로 바꿔야 한다면 선언문 하나만 변경하면 나머지 코드는 컴토하지 않아도 된다. 참조변수의 타입이 List이므로 List에 정의되지 않은 메서드는 사용되지 않았을 것이 확실하기 때문이다. 그러나 참조변수 타입을 ArrayList로 했다면, 선언문 이후의 문장들을 검토해야 한다.
List에 정의되지 않은 메서드를 호출했을 수 있기때문이다.
Map인터페이스를 구현한 컬렉션 클래스는 키(key)와 값(value)을 쌍(pair)으로 저장하고 있기 때문에 iterator()를 직접 호출할 수 없고, 그 대신 keySet()이나 entrySet()과 같은 메서드를 통해서 키와 값을 각각 따로 Set의 형태로 얻어 온 후에 다시 iterator()를 호출해야 Iterator를 얻을 수 있다.
예시
1 2 3 4 5 6 7 8 9 10 11 12 13 | package sungju.Java.Test3; import java.util.Map; import java.util.HashMap; import java.util.Iterator; public class Test3 { public static void main(String[] args) { Map map = new HashMap(); //... Iterator it = map.keySet().iterator(); } } |
1.8.3 ListIterator
: ListIterator는 Iterator를 상속받아서 기능을 추가한 것으로, 컬렉션의 요소에 접근할 때 Iterator는 단방향으로만 이동할 수 있는데 반해 ListIterator는 양방향으로의 이동이 가능하다.
단, ArrayList나 LinkedList와 같이 List인터페이스를 구현한 컬렉션에서만 사용할 수 있다.
- ListIterator : Iterator에 양방향 조회기능추가(List를 구현한 경우만 사용가능
1.8.4 ListIterator의 메서드
메서드 |
설명 |
void add(Object o) |
컬렉션에 새로운 객체(o)를 추가한다. (선택적 기능) |
boolean hasNext() |
읽어 올 다음 요소가 남아있는지 확인한다. 있으면 true, 없으면 false를 반환 |
boolean hasPrevious() |
읽어 올 이전 요소가 남아있는지 확인한다. 있으면 true, 없으면 false를 반환 |
Object next() |
다음 요소를 읽어 온다. next()를 호출하기 전에 hasNext()를 호출해서 읽어 올 요소가 있는지 확인하는 것이 안전하다. |
Object previous() |
이전 요소를 읽어 온다. previous()를 호출하기 전에 hasPrevious()를 호출해서 읽어 올 요소가 있는지 확인하는 것이 안전하다. |
int nextIndex() |
다음 요소의 index를 반환한다. |
int previousIndex() |
이전 요소의 index를 반환한다. |
void remove() |
next() 또는 previous()로 읽어 온 요소를 삭제한다. 반드시 next()나 previous()를 먼저 호출한 다음에 이 메서드를 호출해야한다. (선택적 기능) |
void set(Object o) |
next() 또는 previous()로 읽어 온 요소를 지정된 객체(o)로 변경한다. 반드시 next()나 previous()를 먼저 호출한 다음에 이 메서드를 호출해야한다. (선택적 기능) |