티스토리 뷰
자바 컬렉션
1. 서론
1.1 알아두기 : java.util 패키지의 구성
- 컬렉션 프레임웍(Collection Framework) : 다수의 데이터를 쉽게 처리할 수 있는 표준화된 방법을 제공
하는 클래스들
- 유용한 클래스 : 알아두면 좋은 자주 쓰이는 클래스들
- 형식화 클래스 : 데이터를 표준화도니 형식으로 출력하는데 도움을 주는 클래스들
1.2 컬렉션 프레임웍
* 컬렉션 : 다수의 데이터 즉, 데이터 그룹
* 프레임웍 : 표준화된 프로그래밍 방식
* 컬렉션 클래스 : 다수의 데이터를 저장할 수 있는 클래스
--> 컬렉션 프레임웍 : 데이터군을 저장하는 클래스들을 표준화한 설계. JDK1.2 이전까지는 Vector,
Hashtable, Properties 와 같은 컬렉션 클래스들을 서로 다른 각자의 방식으로 처리해야 했으나,
JDK1.2 부터는 컬렉션프레임웍이 등장하면서 다양한 종류의 컬렉션 클래스가 추가되고 모든 컬렉션
클래스를 표준화도니 방식으로 다룰 수 있도록 체계화되었다.
2. 본론
2.1 컬렉션 프레임웍의 핵심 인터페이스 - List, Set, Map
2.2 컬렉션 프레임웍의 핵심 인터페이스와 특징
인터페이스 |
특 징 |
List |
순서가 있는 데이터의 집합. 데이터의 중복을 허용한다. 저장순서에 의해 접근. 예) 대기자 명단 |
구현클래스 : ArrayList, LinkedList, Stack, Vector 등 | |
Set |
순서를 유지하지 않는 데이터의 집합. 데이터의 중복을 허용하지 않는다. 예) 양의 정수집합, 소수의 집합 등 |
구현클래스 : HashSet, TreeSet 등 | |
Map |
키(key)와 값(value)의 쌍(pair)으로 이루어진 데이터의 집합 순서는 유지되지 않으며, 키는 중복을 허용하지 않고, 값은 중복을 허용한다. 키에 의한 데이터 접근 가능 예) 우편번호, 지역번호(전화번호) |
구현클래스 : HashMap, TreeMap, Hashtable, Properties 등 |
2.3 Collection 인터페이스 : 최상위 인터페이스
메소드 |
설명 |
int size() |
컬렉션에 저장된 객체의 개수 반환 |
boolean isEmpty() |
컬렉션이 비어있는지 확인 |
boolean add(E o) |
지정된 객체를 컬렉션에 추가 |
boolean remove(O o) |
지정된 객체를 삭제 |
void clear() |
컬렉션의 모든 객체를 삭제 |
Object[] toArray() |
컬렉션에 있는 요소를 객체배열로 바꾼다. |
2.4 List 인터페이스
메소드 |
설명 |
int indexOf(O o) |
지정된 객체의 위치를 반환(첫번째 요소부터 순방향) |
int lastIndexOf(O o) |
지정된 객체의 위치를 반환(마지막 요소부터 역방향) |
E get(int index) |
index 위치의 객체를 반환 |
E set(int index, E element) |
지정된 위치(index)에 객체(element)를 저장(덮어쓰기) |
void add(int index, E element) |
주어진 index에 객체 저장.(밀어내기) |
E remove(int index) |
index 위치의 객체 지우고 삭제된 객체 반환 |
2.5 Set 인터페이스 : 생략
2.6 Map 인터페이스
메소드 |
설명 |
int size() |
저장된 key-value쌍의 개수 반환 |
boolean isEmpty() |
Map 이 비어있는지 확인 |
V put(K key, V value) |
Map 에 있는 value객체를 key 객체에 연결하여 저장 |
V get(O key) |
지정된 key객체에 대응하는 value객체를 찾아서 반환 |
V remove(O key) |
지정한 key객체와 일치하는 key-value 객체를 삭제 |
boolean containsKey(O key) |
key 객체와 일치하는 key 객체가 있는지 확인 |
boolean containsValue(O value) |
value 객체와 일치하는 value객체가 있는지 확인 |
2.7 ArrayList 와 Vector 클래스
<공통점>
- 컬렉션 프레임웍에서 가장 많이 사용되는 컬렉션 클래스
- List 인터페이스를 구현
- 저장 순서가 유지되고 중복을 허용
- 데이터의 저장 공간으로 배열을 사용한다
- 다른종류의 데이터형을 가진 데이터요소를 가질 수 있음
- 가득 차게 되면 자동으로 저장 영역을 늘려줌
- 오토박싱 / 언박싱. 기본데이터형 변수를 저장하는 것도 가능
- 시퀸스(Sequence) 데이터 구조 : 순차적인 인덱스값에 대한 위치로 접근
- 인덱스값을 이용해서 자료구조의 임의의 지점에서 저장 및 접근이 가능
<차이점>
- Vector 는 멀티쓰레드에 대한 동기화가 되어 있으나, ArrayList 는 동기화 처리가 되어 있지 않다.
** 동기화(Synchronization) : 멀티쓰레드 프로그래밍에서는 하나의 객체를 여러 쓰레드가 동시에
접근할 수 있기 때문에 데이터의 일관성을 유지하기 위해서는 동기화가 필요하다. 그러나, 멀티
쓰레드 프로그래밍이 아닌 경우에는 불필요한 기능이 되어 오히려 성능을 떨어뜨리는 요인이
된다. 그래서 새로 추가된 ArrayList 와 HashMap 같은 컬렉션에서는 동기화를 자체적으로 하지
않고, 필요할 경우 동기화 메서드를 이용해서 동기화 처리가 가능하도록 변경하였다.
** 배열을 이용한 자료 구조 : 데이터를 읽어오고 저장하는데는 효율성이 좋지만 용량을 변경해야
할때는 새로운 배열을 생성한 후 기존의 데이터를 새로운 배열로 복사해야 하기 때문에 효율이
떨어짐.
** ArrayList 는 기존의 Vector 를 개선한 것으로 Vector 와 구현원리와 기능적인 측명이 동일하다.
Vector 는 기존에 작성된 소스와의 호환성을 위해 계속 남겨두고 있을 뿐이므로 가능하면
ArrayList 를 사용하자.
** 메소드 (Vector 기준)
구분 |
메소드 |
설명 |
생성자 |
Vector() |
디폴트생성자 |
Vector(int capa) |
주어진 capa만큼의 저장 공간을 가직 백터 생성 | |
Vector(int capa, int capaincre) |
주어진 capa 의 저장 공간을 정해주고 저장 공간이 다 차게 되면 capaincrement 만큼 저장공간을 늘려준다. | |
저장 |
boolean add(E o) |
객체를 저장함. 맨뒤에 붙이기 |
boolean add(int index, E element) |
index 로 지정된 위치에 객체 저장 (밀어내기) | |
E set(int index, E element) |
index 로 지정된 위치에 객체 교환 (덮어쓰기) | |
접근 |
E get(int index) |
index 로 지정된 요소 반환 |
E firstElement() |
Vector 의 첫 번째 요소를 반환 | |
E lastElement() |
Vector 의 마지막 요소를 반환 | |
삭제 |
E remove(int index) |
index 로 주어진 위치에 존재하는 객체 지우고 지워진 객체반환 |
boolean remove(O o) |
주어진 객체와 같은 객체를 지우기. 단, 첫 번째 객체의 레퍼런스만 지워짐 (이동일어남. 자리채우기) | |
void clear() |
Vector 에 저장된 모든 객체 지우기 | |
찾기 |
boolean contains(O elem) |
특정객체의 백터포함 여부 |
int indexOf(O elem) |
해당 객체의 위치 반환 | |
int lastIndexOf(O elem) |
해당 객체의 마지막 위치를 반환 | |
int size() |
벡터안의 객체 수를 반환 | |
boolean isEmpty() |
벡터가 비어있는지 확인. 비어 있으면 true |
2.8 LinkedList 클래스
** 배열 : 가장 기본적인 형태의 자료구조로 구조가 간단하여 사용하지 쉽고 데이터를 읽어오는데 걸리는
시간(접근시간, access time)이 가장 빠르다.
- 단점 1) 크기를 변경할 수 없다
2) 비순차적인 데이터의 추가 또는 삭제에 시간이 많이 걸림.
---> LinkedList 는 이러한 단점을 보완하기 위해 고안됨. LinkedList 는 불연속적으로 존재하는 데이터를
서로 연결한 형태. LinkedList 의 각 요소들은 자신과 연결된 다음 요소에 대한 참조(주소값)와
데이터로 구성되어 있다.
** LinkedList 의 데이터 삭제
: 삭제하고자 하는 요소의 이전 요소가 삭제하고자 하는 요소의 다음 요소를 참조하도록 변경하기만
하면 됨. 처리 속도가 빠름
** LinkedList 의 데이터 추가
: 새로운 요소를 생성한 다음 추가하고자 하는 위치의 이전 요소의 참조를 새로운 요소에 대한 참조로
변경해 주고 새로운 요소가 그 다음 요소를 참조하도록 변경하기만 하면 됨. 처리속도가 빠름.
** LinkedList 는 이동방향이 단방향이기 때문에 다음 요소에 대한 접근은 쉽지만 이전요소에 대한 접근
은 어렵다. 이점을 보완한 것이 <더블링크드리스트(doublelinkedlist)> 이다. 링크드리스트보다 더
많이 사용됨.
2.9 ArrayList 와 LinkedList 의 비교
** 데이터의 추가 / 삭제 비교
import java.util.*; public class ArrayListLinkedListTest { public static void main(String args[]) { // 추가할 데이터의 개수를 고려하여 충분히 잡아야한다. ArrayList al = new ArrayList(1000000); LinkedList ll = new LinkedList(); System.out.println("= 순차적으로 추가하기 ="); System.out.println("ArrayList :"+add1(al)); System.out.println("LinkedList :"+add1(ll)); System.out.println(); System.out.println("= 중간에 추가하기 ="); System.out.println("ArrayList :"+add2(al)); System.out.println("LinkedList :"+add2(ll)); System.out.println(); System.out.println("= 중간에서 삭제하기 ="); System.out.println("ArrayList :"+remove2(al)); System.out.println("LinkedList :"+remove2(ll)); System.out.println(); System.out.println("= 순차적으로 삭제하기 ="); System.out.println("ArrayList :"+remove1(al)); System.out.println("LinkedList :"+remove1(ll)); } public static long add1(List list) { long start = System.currentTimeMillis(); for(int i=0; i<100000;i++) list.add(i+""); long end = System.currentTimeMillis(); return end - start; } public static long add2(List list) { long start = System.currentTimeMillis(); for(int i=0; i<1000;i++) list.add(500, "X"); long end = System.currentTimeMillis(); return end - start; } public static long remove1(List list) { long start = System.currentTimeMillis(); for(int i=list.size()-1; i > 0;i--) list.remove(i); long end = System.currentTimeMillis(); return end - start; } public static long remove2(List list) { long start = System.currentTimeMillis(); for(int i=0; i<1000;i++) list.remove(i); long end = System.currentTimeMillis(); return end - start; } } |
** 결과
= 순차적으로 추가하기 = ArrayList : 591 LinkedList : 721 = 중간에 추가하기 = ArrayList : 3465 LinkedList : 10 = 중간에 삭제하기 = ArrayList : 3415 LinkedList : 10 = 순차적으로 삭제하기 = ArrayList : 10 LinkedList : 50 |
<결론1> 순차적으로 추가/삭제하는 경우에는 ArrayList 가 LinkedList 보다 빠르다.
<결론2> 중간에 데이터를 추가/삭제하는 경우에는 LinkedList 가 ArrayList 보다 빠르다.
** 데이터의 접근
import java.util.*; public class ArrayListLinkedListTest2 { public static void main(String args[]) { ArrayList al = new ArrayList(1000000); LinkedList ll = new LinkedList(); add(al); add(ll); System.out.println("= 접근시간테스트 ="); System.out.println("ArrayList :"+access(al)); System.out.println("LinkedList :"+access(ll)); } public static void add(List list) { for(int i=0; i<100000;i++) list.add(i+""); } public static long access(List list) { long start = System.currentTimeMillis(); for(int i=0; i<10000;i++) list.get(i); long end = System.currentTimeMillis(); return end - start; } } |
** 결과
= 접근시간테스트 = ArrayList : 10 LinkedList : 3195 |
--> 배열은 각 요소들이 연속적으로 메모리상에 존재하기 때문에 간단한 계산만으로 원하는 데이터의
주소를 얻어서 저장된 데이터를 곧바로 읽어올 수가 있지만, LinkedList 는 각 요소들이 불연속적으로
연결되어 있어서 처음부터 n번째 데이터까지 차례대로 따라가야만 원하는 값을 얻을 수 있다.
그래서, LinkedList 는 저장해야하는 데이터의 개수가 많아질 수록 데이터를 읽어 오는 시간, 즉
접근시간(access time)이 길어진다는 단점이 있다.
컬렉션 |
읽기(접근시간) |
추가 / 삭제 |
비 고 |
ArrayList |
빠르다 |
느리다 |
순차적인 추가삭제는 빠름 비효율적인 메모리 사용 |
LinkedList |
느리다 |
빠르다 |
데이터가 많을 수록 접근성이 떨어짐 |
<결론> 다루고자 하는 데이터의 개수가 변하지 않는 경우라면, ArrayList 가 최상의 선택이 되겠지만,
데이터의 개수가 변경이 잦다면 LinkedList 를 사용하는 것이 더 나은 선택이 될 것이다.
**두 클래스의 장점을 이용해서 두 클래스를 혼합해서 사용하는 방법도 있다. 처음 작업하기 전에
데이터를 저장할 때는 ArrayList 를 사용한 다음 작업할 때는 LinkedList 로 데이터를 옮겨서 작업
하면 좋은 효율을 얻을 수 있다.
2.10 Stack 과 Queue
** Stack 클래스 : 요소를 데이터 구조의 한쪽 단에서만 저장/접근할 수 있는 컬렉션
LIFO (last in first out)
구분 |
Stack 클래스 |
Queue 인터페이스 |
구조 |
LIFO |
FIFO |
생성 |
new 연산자로 생성 Stack s = new Stack(); |
queue인터페이스를 구현한 클래스로 생성 Queue q = new LinkedList(); |
메소드 |
E push() : 맨 위에 객체 추가 |
boolean offer(E o) : 큐에 객체 넣기 |
E pop() : 맨위 객체를 반환. 맨위 객체 제거됨(꺼내기) |
E poll() : 큐에서 데이터 꺼내기 (비어있으면 null. 자리이동 일어남) | |
E peek() : 맨 위 객체 반환 (객체 제거 안됨) |
E peek() : 맨 아래 객체 반환 (객체 제거 안됨) | |
boolean empty() : 스택이 비었는지 확인 |
| |
활용 예 |
수식 계산, 수식 괄호 검사, 워드의 undo/redo, 웹브라우저의 뒤로/앞으로 |
최근 사용문서, 인쇄 작업 대기목록, 버퍼 |