다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합
즉, 데이터를 저장하는 자료 구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해 놓은 것
이러한 컬렉션 프레임워크는 자바의 인터페이스(interface)를 사용하여 구현된다
컬렉션은 다수의 데이터를 쉽게 다루는데 매우매우 유용함
데이터를 저장하는 자료 구조에 따라 핵심이 되는 주요 인터페이스를 정의하고 있다
구조상의 차이로 인해 Map 인터페이스는 Collection 인터페이스를 상속받지않고 별도로 정의된다
위 사진을 통해 컬렉션 프레임워크를 구성하는 모든 클래스가 제네릭으로 표현되어 있음도 알 수 있다
컬렉션 클래스(collection class)
컬렉션 프레임워크에 속하는 인터페이스를 구현한 클래스를 부르는 말
컬렉션 프레임워크의 모든 컬렉션 클래스는 List와 Set, Map 인터페이스 중 하나의 인터페이스를 구현하고 있다
컬렉션 인터페이스(collection interface)
List, Set, Queue 인터페이스의 많은 공통된 부분을 Collection 인터페이스에서 정의한다
따라서 Collection 인터페이스는 컬렉션을 다루는데 가장 기본적인 동작들을 정의하고, 그것을 메소드로 제공해준다
주요 메소드
boolean add(E e)
: 해당 컬렉션에 전달된 요소를 추가
void clear()
: 해당 컬렉션의 모든 요소를 제거
boolean contains(Object o)
: 해당 컬렉션이 전달된 객체를 포함하고 있는지를 확인
boolean equals(Object o)
: 해당 컬렉션과 전달된 객체가 같은지를 확인
boolean isEmpty()
: 해당 컬렉션이 비어있는지를 확인
Iterator<E> iterator()
: 해당 컬렉션의 반복자(iterator)를 반환
boolean remove(Object o)
: 해당 컬렉션에서 전달된 객체를 제거
int size()
: 해당 컬렉션의 요소의 총 개수를 반환
Object[] toArray()
: 해당 컬렉션의 모든 요소를 Object 타입의 배열로 반환
컬렉션에서 동작하거나 컬렉션을 반환하는 클래스 메소드만으로 이루어진 클래스
Collection은 인터페이스이고 Collections는 클래스라는 것에 주의
List 인터페이스를 구현한 클래스로 순서가 존재하고 중복을 허용하는 클래스
종류:
1. ArrayList
2. LinkedList
3. Vector
4. Stack
배열을 이용하여 데이터를 저장하는 클래스
인덱스를 이용해 배열 요소에 빠르게 접근할 수 있지만 배열은 크기를 변경할 수 없기 때문에 이를 옮기고 하는 과정에서 시간이 사용된다
근데 그러면 배열을 쓰지 왜 ArrayList를 쓰는거?
- 배열은 크기가 고정되어 있기 때문에 변경이 불가능하다
=> 성능이 중요할 때 사용하기 좋음- ArrayList는 배열을 통해 값을 저장하긴 하지만 동저으로 변하는 것을 자동으로 처리해 주기 때문에 편리하다
=> ArrayList와 같은 Collection 구현체는 동적으로 크기가 변경될 때, 추가적인 기능이 필요할 때 사용하기 좋다
+) Arrays 클래스는 배열 조작에 필요한 유틸리티 기능을 제공할 뿐 데이터를 저장하는 용도는 아니다
import java.util.*
ArrayList<Integer> arrList = new ArrayList<Integer>();
arrList.add(40);
arrList.add(20);
arrList.add(30);
arrList.add(10);
for (int i = 0; i < arrList.size(); i++){
System.out.print(arrList.get(i) + " ");
}
// 입력받은 index에 해당하는 값을 제거
arrList.remove(1);
for (int e : arrList) {
System.out.print(e + " ");
}
// Collections.sort() 메소드를 이용한 요소의 정렬
Collections.sort(arrList);
// iterator() 메소드와 get() 메소드를 이용한 요소의 출력
Iterator<Integer> iter = arrList.iterator();
while (iter.hasNext()) {
System.out.print(iter.next() + " ");
}
// set() 메소드를 이용한 요소의 변경
arrList.set(0, 20);
for (int e : arrList) {
System.out.print(e + " ");
}
System.out.println("리스트의 크기 : " + arrList.size());
// 실행결과
// 40 20 30 10
// 40 30 10
// 10 30 40
// 20 30 40
// 리스트의 크기 : 3
LinkedList 클래스
연결 리스트(linked list)를 이용하여 요소를 저장합니다.
ArrayList 클래스가 배열을 이용하여 요소를 저장함으로써 발생하는 단점을 극복하기 위해 고안됨
연결리스트는 데이터의 추가와 삭제가 매우 쉽다
하지만 단일 연결리스트는 이전 값에 접근하는 것이 매우 어려움
그래서 이중 연결리스트를 더 자주 사용함
(아래 코드와 같이 일반적으로 LinkedList는 양방향 연결 리스트이고 단일 연결 리스트를 구현하려면 직접 구현해야함)
import java.util.*
LinkedList<String> lnkList = new LinkedList<String>();
lnkList.add("넷");
lnkList.add("둘");
lnkList.add("셋");
lnkList.add("하나");
// for 문과 get() 메소드를 이용한 요소의 출력
for (int i = 0; i < lnkList.size(); i++) {
System.out.print(lnkList.get(i) + " ");
}
// remove() 메소드를 이용한 요소의 제거
lnkList.remove(1);
// Enhanced for 문과 get() 메소드를 이용한 요소의 출력
for (String e : lnkList) {
System.out.print(e + " ");
}
// set() 메소드를 이용한 요소의 변경
lnkList.set(2, "둘");
for (String e : lnkList) {
System.out.print(e + " ");
}
System.out.println("리스트의 크기 : " + lnkList.size());
위와 같이 연결리스트는 저장하는 내부 방식이 다를 뿐 ArrayList의 사용방식과 동일하다
Vector 클래스
ArrayList와 같은 기능을 제공하며 코드 호화성을 위해 아직 남아 있음
Stack 클래스
Vector 클래스를 상속받아서 스택 메모리 구조의 클래스를 제공
스택 메모리 구조: 선형 메모리 공간에 데이터를 저장하면서 후입선출(LIFO)의 시멘틱을 따르는 자료 구조 (다 알죠?)
Stack 클래스는 스택 메모리 구조를 표현하기 위해, Vector 클래스의 메소드를 5개만 상속받아 사용한다
boolean empty()
: 해당 스택이 비어 있으면 true를, 비어 있지 않으면 false를 반환
E peek()
: 해당 스택의 제일 상단에 있는(제일 마지막으로 저장된) 요소를 반환
E pop()
: 해당 스택의 제일 상단에 있는(제일 마지막으로 저장된) 요소를 반환하고, 해당 요소를 스택에서 제거
E push(E item)
: 해당 스택의 제일 상단에 전달된 요소를 삽입
int search(Object o)
: 해당 스택에서 전달된 객체가 존재하는 위치의 인덱스를 반환
(이때 인덱스는 제일 상단에 있는(제일 마지막으로 저장된) 요소의 위치부터 0이 아닌 1부터 시작)
import java.util.*
Stack<Integer> st = new Stack<Integer>();
//Deque<Integer> st = new ArrayDeque<Integer>(); 더 빠른 스택 구현 가능
// but Deque 인터페이스를 구현하기 때문에 search() 메소드는 지원하지 않음
st.push(4);
st.push(2);
st.push(3);
st.push(1);
System.out.println(st.peek());
System.out.println(st);
System.out.println(st.pop());
System.out.println(st);
System.out.println(st.search(4));
System.out.println(st.search(3));
// 실행결과
// 1
// [4, 2, 3, 1]
// 1
// [4, 2, 3]
// 3
// 1
queue 메모리 구조를 구현하기 위해 제공되는 인터페이스
큐 메모리 구조: 선형 메모리 공간에 데이터를 저장하면서 선입선출(FIFO)의 시멘틱을 따르는 자료 구조
Queue 인터페이스를 상속받는 인터페이스:
1. Deque
2. BlockingDeque
3. BlockingQueue
4. TransferQueue
위 4개도 역시 인터페이스 이고 자주 사용하는 LinkedList는 List 인터페이스를 구현한 List 컬렉션 클래스임에 동시에 Deque 인터페이스도 구현한다
Queue 인터페이스는 큐 메모리 구조를 표현하기 위해, 다음과 같은 Collection 인터페이스 메소드만을 상속받아 사용한다
boolean add(E e)
: 해당 큐의 맨 뒤에 전달된 요소를 삽입
(삽입에 성공하면 true를 반환하고, 큐에 여유 공간이 없어 삽입에 실패하면 IllegalStateException을 발생시킴)
E element()
: 해당 큐의 맨 앞에 있는(제일 먼저 저장된) 요소를 반환
boolean offer(E e)
: 해당 큐의 맨 뒤에 전달된 요소를 삽입
(삽입에 성공하지 못하면 false 를 반환)
E peek()
: 해당 큐의 맨 앞에 있는(제일 먼저 저장된) 요소를 반환
(만약 큐가 비어있으면 null을 반환)
E poll()
: 해당 큐의 맨 앞에 있는(제일 먼저 저장된) 요소를 반환하고, 해당 요소를 큐에서 제거
(만약 큐가 비어있으면 null을 반환)
E remove()
: 해당 큐의 맨 앞에 있는(제일 먼저 저장된) 요소를 제거
import java.util.*
LinkedList<String> qu = new LinkedList<String>(); // 큐의 생성
//Deque<String> qu = new ArrayDeque<String>(); 더 빠른 queue 구현 가능
qu.add("넷");
qu.add("둘");
qu.add("셋");
qu.add("하나");
System.out.println(qu.peek());
System.out.println(qu);
System.out.println(qu.poll());
System.out.println(qu);
qu.remove("하나");
System.out.println(qu);
// 실행결과
// 넷
// [넷, 둘, 셋, 하나]
// 넷
// [둘, 셋, 하나]
// [둘, 셋]