Framework의 이해
프레임워크는 여러 분야에서 사이한 개념으로 사용되기 때문에 이에 대한 정확한 의미 파악은 쉽지 않다. 하지만 공통적으로 "잘 정의된 구조 또는 골격" 이라는 의미를 가진다.
따라서 자바에서 말하는 프레임워크는 "잘 정의된 구조의 클래스들" 이라 볼 수 있다. 즉 프레임워크는 프로그래머들이 쓸 수 있도록 잘 정의된 클래스들의 모임이라 할 수 있는데, 이는 '라이브러리'라 불리게 된다. 하지만 '컬렉션 라이브러리'가 아닌 '컬렉션 프레임워크'라 한다. 그 이유는 관련된 클래스의 정의에 적용되는 설계 원칙 또는 구조가 존재하기 때문이다.
Collection Framework
데이터의 저장 방법, 그리고 이와 관련 있는 알고리즘에 대한 프레임워크이다. 자료구조, 알고리즘, 제네릭 기반의 클래스와 메소드로 미리 구현해 놓은 결과물이며 컬렉션 프레임워크를 이용하면 자료구조를 몰라도 트리 기반의 데이터, 알고리즘을 몰라도 이진 탐색을 수행할 수 있다.
한마디로 잘 짜여진 골격이라 할 수 있고, 직접 알고리즘을 짜지 않고 최적을 성능을 낼 수 있는 라이브러리라 볼 수 있다.
Collection Framework의 골격
Iterable
Iterable 인터페이스는 컬렉션에 대한 반복(iteration)을 가능하게 한다.. 자바의 컬렉션은 여러 요소를 담을 수 있는 자료구조를 의미하고, Array, List, Set, Map 등이 해당된다.
Iterable Interface는 다음과 같이 선언 되어있다.
public interface Iterable<T> {
Iterator<T> iterator();
}
제네릭 타입을 사용하고 있으며 다양한 종류의 요소를 담는 컬렉션을 다룰 수 있다. iterator 메서드는 해당 컬렉션을 순회할 수 있는 Iterator 객체를 반환한다.
Iterator 인터페이스는 다음과 같이 선언 되어있다.
public interface Iterator<T> {
boolean hasNext();
T next();
void remove();
}
hasNext() | 다음 요소가 있는지 여부를 확인한다. |
next() | 다음 요소를 반환한다. |
remove() | 현재 요소를 삭제한다. |
사용예제
public class IteratorEx {
public static void main(String[] args) {
// 문자열을 저장하는 ArrayList 생성
List<String> stringList = new ArrayList<>();
stringList.add("A");
stringList.add("B");
stringList.add("C");
// Iterator를 사용하여 리스트 순회
Iterator<String> iterator = stringList.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
System.out.println(language);
}
}
}
Collection
Collection 인터페이스는 자바 컬렉션 프레임워크의 최상위 인터페이스 중 하나이다. 이 인터페이스는 객체 그룹을 나타내며, 객체들을 담고 관리하는데 사용되는 일반적인 메서드를 정의한다. Collection은 많은 하위 인터페이스와 클래스들의 기반이 되며, List, Set, Queue 등 다양한 컬렉션 타입을 표현한다.
주요 메소드
size() | 컬렉션에 포함된 요소의 개수를 반환한다. |
isEmpty() | 컬렉션이 비어있는지 여부를 반환한다. |
contains(Object o) | 지정된 요소가 컬렉션에 포함되어 있는지 여부를 반환한다. |
iterator() | 컬렉션을 순회하는 데 사용할 수 있는 Iterator 객체를 반환한다. |
toArray() | 컬렉션에 포함된 모든 요소를 배열로 반환한다. |
add(E e) | 지정된 요소를 컬렉션에 추가한다. |
remove(Object o) | 지정된 요소를 컬렉션에서 제거한다. |
containsAll(Collection c) | 컬렉션에 지정된 컬렉션의 모든 요소가 포함되어 있는지 여부를 반환한다. |
addAll(Collection c) | 지정된 컬렉션의 모든 요소를 현재 컬렉션에 추가한다. |
removeAll(Collection c) | 현재 컬렉션에서 지정된 컬렉션의 모든 요소를 제거한다. |
retainAll(Collection c) | 현재 컬렉션에서 지정된 컬렉션에 포함된 요소 이외의 모든 요소를 제거한다. |
clear() | 컬렉션의 모든 요소를 제거한다. |
List
List 인터페이스는 순서가 있는 컬렉션을 나타내는 인터페이스이다. 클래스들은 요소의 순서를 유지하며, 인덱스(index)를 사용하여 각 요소에 접근할 수 있다. 또한 List는 배열과 유사한 방식으로 요소를 다룰 수 있고, 중복된 요소를 허용한다.
특징
- 요소들의 순서가 유지된다. 이는 요소가 리스트에 추가된 순서대로 인덱스가 할당되어 있음을 의미한다.
- 인덱스 기반 접근이 가능하 각 요소는 0부터 시작하는 인덱스를 가지고 있습니다. 따라서 인덱스를 통해 요소에 직접 접근할 수 있다.
- 동일한 요소를 중복해서 저장할 수 있다.
- 리스트의 크기를 동적으로 변경할 수 있다.
주요메소드
get(int index) | 지정된 인덱스에 있는 요소를 반환한다. |
set(int index, E element) | 지정된 인덱스에 새로운 요소를 설정한다. |
add(int index, E element) | 지정된 위치에 요소를 추가한다. |
remove(int index) | 지정된 인덱스에 있는 요소를 제거하고 반환한다. |
indexOf(Object o) | 지정된 객체의 인덱스를 반환한다. |
lastIndexOf(Object o) | 지정된 객체의 마지막으로 등장하는 인덱스를 반환한다. |
listIterator() | 리스트의 반복자(ListIterator)를 반환한다. |
listIterator(int index) | 지정된 위치에서 시작하는 리스트의 반복자(ListIterator)를 반환한다. |
subList(int fromIndex, int toIndex) | 지정된 범위의 요소로 이루어진 부분 리스트를 반환한다. |
ArrayList
Arraylist 클래스는 동적 배열 구현체로 크기를 동적으로 조절할 수 있는 배열이다. 이는 배열과 리스트의 결합체로, 배열의 장점과 리스트의 유연성을 모두 제공한다.
특징
- 크기를 동적으로 조절할 수 있다. 요소를 추가하거나 제거할 때 자동으로 크기가 조절되며, 크기가 자동으로 조절되므로 초기에 크기를 정확히 지정할 필요가 없다.
- 배열과 유사하게 각 요소에 인덱스를 사용하여 직접 접근할 수 있다. 인덱스는 0부터 시작하며, 요소를 가져오거나 설정할 때 사용된다.
- 중복된 요소를 허용한다. 동일한 객체나 값이 여러 번 리스트에 포함될 수 있다.
- 요소를 추가한 순서대로 저장하므로 순서가 유지된다
주요메소드
add(E e) | 리스트의 끝에 요소를 추가한다 |
add(int index, E element) | 지정된 위치에 요소를 삽입한다. |
get(int index) | 지정된 인덱스에 있는 요소를 반환한다. |
size() | 리스트에 포함된 요소의 개수를 반환한다 |
remove(Object o) | 리스트에서 지정된 요소를 제거한다. |
clear() | 리스트의 모든 요소를 제거한다 |
contains(Object o) | 리스트에 지정된 요소가 포함되어 있는지 여부를 반환한다. |
사용 예제
import java.util.ArrayList;
import java.util.List;
public class ArrayListEx {
public static void main(String[] args) {
// ArrayList 생성
List<String> myArrayList = new ArrayList<>();
// 요소 추가
myArrayList.add("A");
myArrayList.add("B");
myArrayList.add("C");
// 요소 접근
System.out.println("Element at index 1: " + myArrayList.get(1));
// 요소 수정
myArrayList.set(1, "Q");
// 요소 삭제
myArrayList.remove("C");
// 리스트 출력
System.out.println("Updated List: " + myArrayList);
}
}
LikedList
LinkedList 클래스는 이중 연결 리스트(Double Linked List) 기반의 리스트 구현체이다. 각 요소는 데이터와 다음 노드, 이전 노드를 참조하는 링크로 이루어져있다. 이 구조는 중간에서의 삽입 및 삭제 작업에 효율적이지만, 특정 인덱스에 직접 접근하는 데는 O(n)이 걸린다.
특징
- 각노드가 이전 노드와 다음 노드를 가리키는는 링크를 가지고 있어, 양쪽 방향으로 탐색이 가능하다.
- 요소의 추가 및 삭제가 발생할 때 동적으로 크기를 조절할 수 있다.
- 특정 인덱스에 직접 접근하는 데는 O(n)이 소요되므로 중간에서의 삽입 및 삭제 작업이 효율적이다.
- 요소는 추가된 순서대로 유지되므로 순서가 중요한 경우 사용된다.
- 각 노드가 데이터와 두 개의 링크를 가지기 때문에 배열 기반의 리스트에 비해 더 많은 메모리를 소비할 수 있다.
주요메소드
add(E e) | 리스트의 끝에 요소를 추가한다. |
add(int index, E element) | 지정된 위치에 요소를 삽입한다. |
get(int index) | 지정된 인덱스에 있는 요소를 반환한다. |
size() | 리스트에 포함된 요소의 개수를 반환한다. |
remove(Object o) | 리스트에서 지정된 요소를 제거한다. |
clear() | 리스트의 모든 요소를 제거한다. |
isEmpty() | 리스트가 비어있는지 여부를 반환한다. |
사용 예제
import java.util.LinkedList;
import java.util.List;
public class LinkedListEx {
public static void main(String[] args) {
// LinkedList 생성
List<String> myLinkedList = new LinkedList<>();
// 요소 추가
myLinkedList.add("A");
myLinkedList.add("B");
myLinkedList.add("C");
// 요소 접근
System.out.println("Element at index 1: " + myLinkedList.get(1));
// 요소 수정
myLinkedList.set(1, "Q");
// 요소 삭제
myLinkedList.remove("C");
// 리스트 출력
System.out.println("Updated List: " + myLinkedList);
}
}
Vector
Vector 클래스는 동기화된(synchronized) 동적 배열 구현체이며, 요소를 배열 기반으로 저장하며 크기를 동적으로 조절할 수 있다.
특징
- 여러 쓰레드에서 동시에 접근하더라도 안전하게 사용할수 있도록 동기화 되어있다. 따라서 멀티스레드 환경에서 안전하게 사용할 수 있지만, 이로 인해 서능이 다소 저하될 수 있다.
- 동적 배열 구현체이므로 요소를 추가하거나 제거할 때 자동으로 크기가 조절된다.
- 각요소에 인덱스를 사용하여 직접 접근 할 수 있다.
- Vector는 컬렉션 프레임워크가 도입되기 이전에 사용되었다. 따라서 최근에는 ArrayList와 같은 클래스가 성능 면에서 더 나은 대안으로 사용되기도 한다.
- 동기화를 지원하므로 여러 쓰레드에서 동시에 접근하는 상황에서 안전하지만, 동기화를 유지하기 위해 락(lock)을 사용하므로 성능에 영향을 줄 수 있다.
주요메서드
add(E e) | 리스트의 끝에 요소를 추가한다 |
add(int index, E element) | 지정된 위치에 요소를 삽입한다. |
get(int index) | 지정된 인덱스에 있는 요소를 반환한다. |
size() | 리스트에 포함된 요소의 개수를 반환한다 |
remove(Object o) | 리스트에서 지정된 요소를 제거한다. |
clear() | 리스트의 모든 요소를 제거한다 |
contains(Object o) | 리스트에 지정된 요소가 포함되어 있는지 여부를 반환한다. |
사용예제
import java.util.Vector;
public class VectorEx {
public static void main(String[] args) {
// Vector 생성
Vector<String> vector = new Vector<>();
// 요소 추가
vector.add("A");
vector.add("B");
vector.add("C");
// 요소 접근
System.out.println("Element at index 1: " + vector.get(1));
// 요소 삭제
vector.remove("C");
// 리스트 출력
System.out.println("Updated Vector: " + vector);
}
}
Stack
Stack 클래스는 후입선출(LIFO, Last In First Out) 구조의 데이터 구조를 구현한 클래스이다. 기본적인 스택 연산을 지원한다. 요소를 스택의 맨 위에(push) 추가하고, 맨위의 요소를 제거(pop)하는 방식으로 동작한다. 가장 최근에 추가된 요소가 가장 먼저 제거되는 구조를 가진다. 또한 Vector 클래스를 상속받아 구현되었기 떄문에 Vector에서 제공되는 모든 메소드를 포함한다. 그리고 스택과 관련이 없는 메소드들은 deprecated로 표시되어 있다.
특징
- 마지막에 추가된 요소가 가장 먼저 제거된다.
- Vector를 상속하고 있기 때문에 그 메소드들도 함꼐 사용가능하다.
- 기본적으로 스레드 동기화가 되어있다. Vector를 상속했기 떄문에 스레드 세이프하다. 최근에는 ArrayDeque나 LinkedList를 사용하는 것을 권장한다.
주요메소드
push(E item) | 스택의 맨 위에 요소를 추가한다. |
pop() | 스택의 맨 위에 요소를 제거하고 반환한다. |
peek() | 스택의 맨위에 있는 요소를 제거하지 않고 반환한다. |
empty() | 스택이 비어 있는지 여부를 확인한다. |
search(Object o) | 스택에서 주어진 요소를 찾아 인덱스를 반환한다. 가장 위에 있는 요소부터 역순으로 탐색한다. |
사용예제
import java.util.Stack;
public class StackEx {
public static void main(String[] args) {
// Stack 생성
Stack<String> stack = new Stack<>();
// 요소 추가 (push)
stack.push("A");
stack.push("B");
stack.push("C");
// 요소 확인 (peek)
System.out.println("Top element: " + stack.peek());
// 요소 제거 (pop)
String poppedElement = stack.pop();
System.out.println("Popped element: " + poppedElement);
// 스택이 비어 있는지 확인 (empty)
System.out.println("Is stack empty? " + stack.empty());
// 스택 출력
System.out.println("Stack: " + stack);
}
}
List 구현체 정리
적절한 상황 | 장점 | 단점 | |
ArrayList | 요소의 추가 및 삭제가 자주 발생하지 않고, 인덱스 기반의 빠른 접근이 필요한 경우. | 인덱스 기반의 접근이 빠르며 배열 기반으로 구현되어 메모리 사용량이 작다. | 중간에서의 요소 추가 및 삭제가 느리고, 배열 복사로 인한 비용이 크. |
LinkedList | 중간에서의 요소 추가 및 삭제가 자주 발생하거나, 요소의 순차적인 접근이 주로 필요한 경우. | 중간에서의 삽입 및 삭제가 빠르며, 노드 기반으로 구현되어 배열보다 메모리 사용량이 크지 않. | 인덱스 기반의 접근이 느리고, 메모리 사용량이 더 많을 수 있다. |
Vector | 스레드 동기화가 필요한 경우. | 스레드 동기화를 지원하므로 여러 스레드에서 안전하게 사용할 수 있다. | 성능 측면에서는 ArrayList를 사용하는 것이 더 효율적이. |
Stack | 스택 자료구조의 동작을 구현해야 하는 경우. | 스택의 특성에 맞게 구현되어 있으며, List 인터페이스를 확장하므로 리스트의 기능과 스택의 동작을 모두 사용할 수 있. | 스택 외의 다른 기능이 필요한 경우에는 다른 클래스를 고려해야 한다. |
Queue
Queue 인터페이스는 선입선출(FIFO, Fisrt-In-First-Oout)의 구조를 나타낸다. 요소를 추가할 때는 한쪽 끝(rear), 요소를 제거할 때는 다른 한쪽 끝(front)에서만 가능하다. 대표적 자료구조 큐 자료구조를 나타내며, 대기열이나 작업 큐 등 다양한 응용 분야에서 활용된다.
주요 클래스는 LinkedList와 PriorityQueue로 LinkedList는 이중 연결리스트를 기반으로 한 구현체로, 큐의 동작을 잘 지원한다. PriorityQueue는 우선순위 큐로 구현된 클래스로 요소들이 우선순위에 따라 정렬된다.
주요 메소드
add(E e) | 큐에 요소를 추가한다. 큐에 공간이 충분하지 않으면 예외가 발생한다. |
offer(E e) | 큐에 요소를 추가한다. 큐에 공간이 충분하지 않으면 false를 반환한다. |
remove() | 큐에 요소를 제거하고 해당 요소를 반환한다. 큐가 비어 있으면 예외가 발생한다. |
poll() | 큐에서 요소를 제거하고 해당 요소를 반환한다. 큐가 비어있으면 null을 반환한다. |
element() | 큐의 맨 앞에 있는 요소를 반환한다. 큐가 비어있으면 예외가 발생한다. |
peek() | 큐의 맨 앞에 있는 요소를 반환한다. 큐가 비어있으면 null을 반환한다. |
사용 예제
public class QueueEx {
public static void main(String[] args) {
// Queue 생성
Queue<String> queue = new LinkedList<>();
// 요소 추가
queue.add("A");
queue.add("B");
queue.add("C");
// 요소 제거
String removedElement = queue.poll();
System.out.println("Removed Element: " + removedElement);
// 큐 출력
System.out.println("Queue: " + queue);
}
}
PriorityQueue
PriorityQueue는 우선순위 큐를 나타내며, 각 요소에 우선순위가 부여되어 있고, 높은 우선순위를 가진 요소가 낮은 우선순위를 가진 요소보다 먼저 처리되는 특성을 갖는다. 기본적으로 작은 요소부터 큰 요소 순서로 우선순위를 부여하며 내림차순으로 커스텀하여 바꿀 수도 있다.
특징
- 각 요소에 우선순위를 부여하고, 기본적으로는 작은 요소가 높은 우선순위를 갖는다.
- 내부적으로는 최소 힙(Min Heap) 구조를 사용한다. 최소 힙은 각 노드의 값이 해당하는 하위 트리의 모든 노드의 값보다 작거나 같은 이진 트리를 말한다. 따라서 최소 힙의 루트에 있는 요소가 가장 작은 요소가 된다.
- 삽입과 삭제 연산은 평균적으로 O(log n)의 시간 복잡도를 가지며, 최악의 경우에도 O(log n)이다. 이는 힙의 특성 때문이다.
- 동적으로 크기 조절이 가능하다. 요소를 추가하거나 제거함에 따라 크기가 자동으로 조절된다.
주요메소드
add(E e) 또는 offer(E e) | 큐에 소로를 추가한다. 큐에 공간이 충분하지 않으며 예외가 발생한다. |
remove() 또는 poll() | 큐에서 우선순위가 가장 높은 요소를 제거하고 반환한다. 큐가 비어있으면 remove()는 예외, poll()은 null을 반환한다. |
element() 또는 peek() | 큐에서 우선순위가 가장 높은 요소를 제거하지 하고 반환한다. 큐가 비어있으면 element()는 예외, peek()는 null을 반환한다. |
size() | 큐에 포함된 요소의 개수를 반환한다. |
clear() | 큐의 모든 요소를 제거한다. |
toArray() | 큐의 요소들을 배열로 반환한다. |
iterator() | 큐를 순회하는데 사용할 수 있는 반복자를 반환한다. |
comparator() | 큐에 사용되는 Comparator를 반환한다. 지정 되지 않았으면 null을 반환한다. |
remove(Object o) | 큐에서 주어진 요소를 제거한다. |
contains(Object o) | 큐가 특정 요소를 포함하고 있는지 여부를 반환한다. |
사용예제
import java.util.PriorityQueue;
public class B_PriorityQueueEx {
public static void main(String[] args) {
// 우선순위 큐 생성
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
// 우선순위 큐 생성 (리버스)
PriorityQueue<Integer> reversedPriorityQueue = new PriorityQueue<>(Collections.reverseOrder());
// 요소 추가
priorityQueue.add(30);
priorityQueue.add(20);
priorityQueue.add(50);
priorityQueue.add(10);
// 요소 제거
int removedElement = priorityQueue.poll();
System.out.println("Removed Element: " + removedElement);
// 우선순위 큐 출력
System.out.println("PriorityQueue: " + priorityQueue);
}
}
Deque
Deque 인터페이스는 double-ended queue의 약자로 양쪽 끝에서 요소의 추가와 제거가 모두 가능한 자료구조를 나타낸다. 한마디로 Queue와 Stack의 기능을 모두 사용 가능하며 양방향에서의 조작이 가능하다.
특징
- Queue와 Stack 기능을 모두 지원하며 양쪽 특성을 가지고 있다.(FIFO 및 LIFO의 지원)
- Deque를 구현하는 여러 클래스를 제공하는데 대표적으로 ArrayDeque와 LinkedList가 있다. ArrayDeque는 동적 배열을 기반으로 한 덱을 구현하며, LinkedList는 이중 연결 리스트를 기반으로 한다. 따라서 구현체를 선택할 때는 사용하려는 기능과 성능 특성을 고려해야 한다.
- 동적으로 크기를 조절할 수 있다. 요소를 추가하거나 제거할 때마다 크기가 조절되며 필요에 따라 자동으로 메모리를 할당하거나 해제한다.
- Queue의 맨 끝과 맨 앞에서의 요소 추가 및 제거 연산은 평균적으로 O(1)의 시간 복잡도를 가진다. 이는 ArrayDeque의 경우가 더 빠르게 수행될 수 있다.
주요메소드
요소 추가및 제거 메소드
addFirst(E e) / offerFirst(E e) | 덱의 맨 앞에 요소를 추가한다. |
addLast(E e) / offerLast(E e) | 덱의 맨 뒤에 요소를 추가한다. |
removeFirst() / pollFirst() | 덱의 맨 앞의 요소를 제거하고 반환한다. |
removeLast() / pollLast() | 덱의 맨 뒤에 요소를 제거하고 반환한다. |
getFirst() / peekFirst() | 덱의 맨 앞에 요소를 반환한다. (예외 / null) |
getLast() / peekLast() | 덱의 맨 뒤에 요소를 반환한다. (예외 / null) |
스택 기능 메소드
push(E e) | 스택의 맨 위에 요소를 추가한다. |
pop() | 스택의 맨 위의 요소를 제거하고 반환한다. |
peek() | 스택의 맨 위의 요소를 반환한다. |
큐 기능 메소드
add(E e) / offer(E e) | 큐의 맨 뒤에 요소를 추가한다. |
remove() / poll() | 큐의 맨 앞의 요소를 제거하고 반환한다. |
element() / peek() | 큐의 맨 앞의 요소를 반환한다. |
ArrayDeque
ArrayDeque 클래스는 동적 배열을 기반으로 한 양방향 큐를 나타낸다. Queue및 스택의 양쪽 끝에서의 연산을 효율적으로 수행할 수 있는 자료구조이다.
특징
- 내부적으로 동적으로 크기가 조절되는 배열을 사용하여 요소를 저장한다. 크기 조절이 필요한 경우에 효율적인 메모리 사용을 가능하게 한다.
- 큐의 양쪽 끝에서의 요소 추가 및 제거 연산은 평균적으로 O(1)의 시간 복잡도를 가지므로 연산 속도가 빠르다.
- FIFO 및 LIFO를 지원한다.
- null값을 요소로 허용한다.
- 단일 쓰레드 환경에서 안전하게 사용할 수 있다. 멀티 쓰레드 환경에서는 동기화를 고려해야 한다.
주요메소드
addFirst(E e) / offerFirst(E e) | 덱의 맨 앞에 요소를 추가한다. |
addLast(E e) / offerLast(E e) | 덱의 맨 뒤에 요소를 추가한다. |
removeFirst() / pollFirst() | 덱의 맨 앞의 요소를 제거하고 반환한다. |
removeLast() / pollLast() | 덱의 맨 뒤에 요소를 제거하고 반환한다. |
getFirst() / peekFirst() | 덱의 맨 앞에 요소를 반환한다. (예외 / null) |
getLast() / peekLast() | 덱의 맨 뒤에 요소를 반환한다. (예외 / null) |
size() | 덱의 현재 요소 개수를 반환한다. |
isEmpty() | 덱이 비어있는지 여부를 반환한다. |
clear() | 덱의 모든요소를 제거한다. |
사용 예제
import java.util.ArrayDeque;
import java.util.Deque;
public class ArrayDequeEx {
public static void main(String[] args) {
// ArrayDeque 생성
Deque<String> arrayDeque = new ArrayDeque<>();
// 양쪽 끝에서의 추가 및 제거
arrayDeque.addFirst("First");
arrayDeque.addLast("Last");
System.out.println("ArrayDeque: " + arrayDeque);
// 양쪽 끝에서의 요소 제거
String firstElement = arrayDeque.removeFirst();
String lastElement = arrayDeque.removeLast();
System.out.println("Removed Elements: " + firstElement + ", " + lastElement);
// 큐와 스택의 특성을 모두 사용
arrayDeque.offer("Queue");
arrayDeque.push("Stack");
System.out.println("ArrayDeque after adding Queue and Stack: " + arrayDeque);
}
}
Set
Set 인터페이스는 중복을 허용하지 않는 집합을 나타낸다. 순서가 없는 자료구조이기 때문에 요소들 간의 순서는 정의되어 있지 않다.
특징
- 동일한 요소가 중복해서 저장될 수 없다. 집합 내에서 각 요소는 유일해야한다.
- 순서가 없는 자료구조이다. 따라서 요소들의 저장 순서가 유지되지 않는다.
- 조루 고유한 값을 저장하고자 할 때 사용된다. 예를 들어 집합 내에는 학생들의 고유한 학번을 저장하는 등의 용도로 활용 될 수 있다.
주요메소드
add(E e) | 집합에 요소를 추가한다.(중복의 경우는 추가되지 않는다.) |
remove(Object o) | 주어진 요소를 집합에서 제거한다. |
contains(Object o) | 주어진 요소가 집합에 포함되어 있는지 여부를 확인한다. |
size() | 집합에 포함된 요소의 개수를 반환한다. |
isEmpty() | 집합이 비어있는지 여부를 확인한다. |
clear() | 집합의 모든요소를 제거하여 비운다. |
HashSet
HashSet 클래스는 해시 테이블을 사용하여 요소를 저장하며, 중복된 요소를 허용하지 않는다.
특징
- 해시 테이블을 사용하여 요소들을 저장하며 검색, 삽입, 삭제 연산에 있어서 평균적으로 O(1)의 성능을 제공한다.
- 동일한 요소를 중복해서 저장하지 않는다. 각 요소는 유일해야한다.
- 요소들의 저장 순서를 보장하지 않는다. 따라서 저장된 순서를 유지하려면 LinkedHashSet을 사용해야한다.
- null 값을 요소로 허용한다. 한 집합내에서 하나의 null 값만 저장된다.
- 동기화를 지원하지 않으므로 멀티스레드 환경에서 사용하려면 외부에서 동기화를 고려해야한다.
주요메소드
add(E e) | 집합에 요소를 추가한다. 중복된 요소는 추가되지 않는다. |
remove(Object o) | 지정된 요소를 제거한다. 제거되면 true, 없으면 false를 반환한다. |
size() | 집합에 포함된 요소 개수를 반환한다. |
isEmpty() | 집합이 비어있는지 여부를 반환한다. |
clear() | 집합의 모든 요소를 제거한다. |
iterator() | 집합을 순회하는 반복자로 변환한다. |
toArray() | 집합의 요소들을 배열로 변환한다. |
addAll(Collection<? extends E> c) | 다른 컬렉션의 모든 요소를 추가한다. |
removeALL(Collection<?> c) | 다른 컬렉션에 포함된 요소들을 집합에서 제거한다. |
retainALL(Collection<?> c) | 다른 컬렉션에 포함된 요소들 이외의 모든 요소를 제거한다. |
hashCode() | 집합의 해시 코드를 반환한다. |
사용예제
import java.util.HashSet;
import java.util.Set;
public class HashSetEx {
public static void main(String[] args) {
// HashSet 생성
Set<String> hashSet = new HashSet<>();
// 요소 추가
hashSet.add("A");
hashSet.add("B");
hashSet.add("C");
hashSet.add("A"); // 중복된 요소는 추가되지 않음
// 요소 출력
System.out.println("HashSet: " + hashSet);
// 요소 삭제
hashSet.remove("C");
// 요소 존재 여부 확인
boolean containsOrange = hashSet.contains("A");
System.out.println("Contains Orange: " + containsA);
}
}
LikedHashSet
LikedHashSet 클래스는 해시 테이블과 연결리스트를 활용하여 요소를 저장하는 특징을 가지고 있다.
특징
- 요소들의 삽입 순서를 보장한다. 요소를 순회할 때 추가한 순서대로 나열된다.
- 중복을 허용하지 않는다.
- 내부적으로는 해시 테이블을 사용하여 빠르게 요소에 접근하고, 연결 리스트를 사용하여 순서를 유지한다.
- null 값을 요소로 허용한다.
주요메소드는 HashSet과 거의 동일하며, 순서를 유지하는 특성이 추가된 것이 주된 차이이다.
사용예제
import java.util.LinkedHashSet;
import java.util.Set;
public class LinkedHashSetEx {
public static void main(String[] args) {
// LinkedHashSet 생성
Set<String> linkedHashSet = new LinkedHashSet<>();
// 요소 추가
linkedHashSet.add("A");
linkedHashSet.add("B");
linkedHashSet.add("C");
// 중복된 요소는 추가되지 않음
linkedHashSet.add("Apple");
// 순서가 유지됨
System.out.println("LinkedHashSet: " + linkedHashSet);
// 요소 삭제
linkedHashSet.remove("B");
// 요소 존재 여부 확인
boolean containsOrange = linkedHashSet.contains("B");
System.out.println("Contains Orange: " + containsB);
}
}
SortedSet
SortedSet 인터페이스는 Set 인터페이스의 하위 인터페이스 이며 정렬된 순서를 유지하며 요소를 저장하는 집합을 나타낸다. 정렬된 순서란, 요소들이 특정 기준에 따라 정렬되어 있다는 것을 의미한다.
특징
- 요소들은 정렬된 순서로 저장되며, 해당 순서를 유지한다.
- 정렬된 순서를 결정하는데에는 Comparator 객체 또는 Natural Ordering이 사용된다.
- 서브셋을 생성하거나 특정 범위의 요소를 검색하는 메서드를 제공한다.
- 정렬된 순서 상에서 첫 번째와 마지막 요소를 반환하는 메서드가 있다.
주요메소드
comparator() | 정렬에 사용되는 Comparator를 반환한다. SortedSet이 Natural Ordering에 따라 정렬되었다면 null을 반환한다. |
subSet(E fromElement, E toElement) | 주어진 범위의 서브셋을 반환한다. fromElement는 포함되고, toElement는 포함되지 않는다. |
headSet(E to Element) | 주어진 요소보다 작은 요소들로 이루어진 서브셋을 반환한다. |
tailSet(E fromElement) | 주어진 요소와 그 이상의 크기를 갖는 요소들로 이루어진 서브셋을 반환한다. |
first() | 정렬된 순서에서 첫 번째 요소를 반환한다. |
last() | 정렬된 순서에서 마지막 요소를 반환한다. |
TreeSet
TreeSet 클래스는 이진 검색 트리 자료구조를 기반으로 하여 요소들을 저장한다. 정렬된 순서를 유지하고 중복된 요소를 허용 하지 않으며, 삽입, 삭제, 검색 연산이 빠르게 수행된다.
특징
- 내부적으로는 이진 검색 트리를 사용하여 요소들을 저장한다. 연산이 평균적으로 O(log n)의 시간 복잡도를 갖는다.
- SortedSet을 구현했기 때문에 요소들은 정렬된 순서로 저장되며, 해당 순서를 유지한다.
- Set 특성을 가지므로 중복된 요소를 허용하지 않는다.
- 정렬에 사용되는 Comparator 객체 또는 Natural Ordering을 화용한다.
- SortedSet의 메서드를 사용하여 서브셋을 생성하거나 특정 범위의 요소를 검색할 수 있다.
주요메소드
add(E e) | 요소를 집합에 추가한다. 중복일 경우 false를 반환한다. |
remove(Object o) | 지정된 요소를 집합에서 제거한다. 제거되면 true, 없으면 fasle를 반환한다. |
contains(Object o) | 지정된 요소가 집합에 포함 여부를 확인한다. |
size() | 집합에 포함된 요소의 갯수를 반환한다. |
isEmpty() | 집합이 비어있는지 여부를 반환한다. |
clear() | 집합의 모든 요소를 제거하여 비운다. |
comparator() | 정렬에 사용되는 Comparator를 반환한다. SortedSet이 Natural Ordering에 따라 정렬되었다면 null을 반환한다. |
subSet(E fromElement, E toElement) | 주어진 범위의 서브셋을 반환한다. fromElement는 포함되고, toElement는 포함되지 않는다. |
headSet(E to Element) | 주어진 요소보다 작은 요소들로 이루어진 서브셋을 반환한다. |
tailSet(E fromElement) | 주어진 요소와 그 이상의 크기를 갖는 요소들로 이루어진 서브셋을 반환한다. |
first() | 정렬된 순서에서 첫 번째 요소를 반환한다. |
last() | 정렬된 순서에서 마지막 요소를 반환한다. |
사용예제
import java.util.TreeSet;
import java.util.Set;
public class TreeSetExa {
public static void main(String[] args) {
// TreeSet 생성
Set<String> treeSet = new TreeSet<>();
// 요소 추가
treeSet.add("A");
treeSet.add("B");
treeSet.add("C");
// 중복된 요소는 추가되지 않음
treeSet.add("B");
// 정렬된 순서 확인
System.out.println("TreeSet: " + treeSet);
// 요소 삭제
treeSet.remove("B");
// 요소 존재 여부 확인
boolean containsOrange = treeSet.contains("A");
System.out.println("Contains Orange: " + containsA);
}
}
Map
Map 인터페이스는 키(key)와 값(value)로 이루어진 데이터 집합을 나타낸다. 각 키는 고유하며 각 키에 연관된 값에 접근하고 조작할 수 있다. 키-값 쌍을 저장하며 키를 기반으로 값을 검색할 수 있다.
특징
- 하나의 Map에서 Key는 고유해야한다. 중복된 키를 허용하지 않는다.
- 각 키는 하나의 값과 연관되어 있다. 연관된 키-값 쌍을 저장하고 관리할 수 있다.
- 키와 값의 순서를 보장하지 않는다. 키 또는 값을 순서가 필요한 경우 LinkedHashMap과 같은 클래스를 사용할 수 있다.
- 특정 클래스를 제외하고 대부분의 Map 구현체는 null키와 null 값을 허용한다.
주요메소드
put(K key, V value) | 특정 키에 값을 연결하고, 이전에 연결된 값이 있었다면 그 값을 반환한다. |
get(Object key) | 지정된 키에 연관된 값을 반환한다. 해당 키가 없으면 null을 반환한다. |
remove(Object key) | 지정된 키와 그에 연관된 값을 맵에서 제거하고 반환한다. |
containsKey(Object key) | 맵에 주어진 키가 포함되어 있는지 여부를 반환한다. |
containsValue(Object value) | 맵에 주어진 값이 하나 이상 존재하는지 여부를 반환한다. |
size() | 맵에 포함된 키-값을 쌍의 개수를 반환한다. |
isEmpty() | 맵이 비어있는지 여부를 반환한다. |
keySet() | 맵의 모든 키를 포함하는 Set을 반환한다. |
values | 맵의 모든 값을 포함하는 Collection을 반환한다. |
entrySet() | 맵의 모든 키-값 쌍을 포함하는 set을 반환한다. |
Hashtable
Hashtable 클래스는 Key와 value으로 이루어진 데이터를 저장하며 각 키는 고유해야 하는 특징이 있다. Key와 Value는 null이 될 수 없다.
특징
- 스레드에 안전하도록 동기화된 메서드로 구성되어 있다. 여러 스레드에서 동시에 접근하더라도 안전하게 사용할 수 있지만 이로 인해 성능이 떨어질 수 있다.
- Key나 Value으로 null을 허용하지 않는다. 허용하려면 HashMap을 고려할 수 있다.
- 내부적으로는 해시 테이블을 사용하여 Key-Value 쌍을 저장한다. 해시 충돌이 발생하면 연결 리스트를 사용하여 충돌을 처리한다.
- 키와 값의 순서를 보장하지 않는다.
주요메소드
put(K key, V value) | 특정 키에 값을 연결하고, 이전에 연결된 값이 있었다면 그 값을 반환한다. |
get(Object key) | 지정된 키에 연관된 값을 반환한다. 해당 키가 없으면 null을 반환한다. |
remove(Object key) | 지정된 키와 그에 연관된 값을 맵에서 제거하고 반환한다. |
containsKey(Object key) | 맵에 주어진 키가 포함되어 있는지 여부를 반환한다. |
containsValue(Object value) | 맵에 주어진 값이 하나 이상 존재하는지 여부를 반환한다. |
size() | 맵에 포함된 키-값을 쌍의 개수를 반환한다. |
isEmpty() | 맵이 비어있는지 여부를 반환한다. |
keys() | 맵의 모든 키를 포함하는 Enumeration을 반환한다. |
elements() | 맵의 모든 값들을 포함하는 Enumeration을 반환한다. |
사용예제
import java.util.Hashtable;
import java.util.Enumeration;
public class HashtableEx{
public static void main(String[] args) {
// Hashtable 생성
Hashtable<String, Integer> hashtable = new Hashtable<>();
// 키-값 쌍 추가
hashtable.put("One", 1);
hashtable.put("Two", 2);
hashtable.put("Three", 3);
// 특정 키에 대한 값 조회
int value = hashtable.get("Two");
System.out.println("Value for key 'Two': " + value);
// 맵의 크기 조회
int size = hashtable.size();
System.out.println("Size of the hashtable: " + size);
// 모든 키 열거(Enumeration) 및 값 출력
Enumeration<String> keys = hashtable.keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
int val = hashtable.get(key);
System.out.println("Key: " + key + ", Value: " + val);
}
// 특정 키 제거
hashtable.remove("Two");
// 제거 후 크기 다시 조회
size = hashtable.size();
System.out.println("Size after removing 'Two': " + size);
}
}
hashtable 보다 HashMap과 Concurrent HashMap이 성능 면에서 더 나은 대안이 될 수 있다. 특별한 상황에서 동기화가 필요하고 null을 허용하지 않아야 하는 경우에는 여전히 사용될 수 있다.
LinkedHashMap
LinkedHashMap 클래스는 해시 테이블을 사용하여 키-값 쌍을 저장하지만, 삽입 순서를 유지하는 특징을 가지고 있다.
특징
- 요소들은 삽입된 순서대로 유지된다. 순회나 이터레이션을 수행할 때 삽입된 순서대로 요소에 접근할 수 있다.
- 내부적으로는 해시 테이블과 함께 이중 연결 리스트를 사용하여 삽입 순서를 기억한다. 이로써 요소의 추가 및 제거가 빠르게 이루어진다.
- 키나 값에 null을 허용한다.
- 해시 테이블을 사용하므로 검색, 삽입, 삭제 등의 연산이 평균적으로O(1)에 가까운 시간 복잡도를 갖는다.
생성자
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
initialCapacity | 초기 용량을 설정한다. 이 값보다 커지면 크기가 자동으로 조정된다. |
loadFactor | 해시 테이블이 얼마나 채워졌을 때 크기를 조정할지 결정하는 비율이다. |
accessOrder | true로 하면 액세스 순서에 따라 맵을 정렬하게 된다. |
사용예제
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapEx {
public static void main(String[] args) {
// LinkedHashMap 생성 (삽입 순서를 기억)
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
// 키-값 쌍 추가
linkedHashMap.put("One", 1);
linkedHashMap.put("Two", 2);
linkedHashMap.put("Three", 3);
// 순서가 보장되어 출력
for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
}
}
HashMap
HashMap 클래스는 키(key)와 값(value)으로 이루어진 데이터의 집합을 효율적으로 저장하고 검색할 수 있는 해시 테이블 기반의 자료구조를 사용한다.
특징
- 해시 테이블을 사용하므로 키를 기반으로 한 검색, 삽입, 삭제 등의 연산이 평균적으로 O(1)에 가까운 시간 복잡도 가진다. 최악의 경우에는 O(n)이 될 수 있다.
- 키나 값에 null을 허용한다.
- 요소들의 순서를 보장하지 않는다. 따라서 순서가 중요한 경우에는 LinkedHashMap을 사용할 수 있다.
- 스레드에 안전하지 않다. 멀티스레드 환경에서는 ConcurrentHashMap을 사용하는 것이 좋다.
생성자
public HashMap(int initialCapacity, float loadFactor)
initialCapacity | 초기 용량. 맵의 크기가 이 값보다 커지면 크기가 자동으로 조정된다. |
loadFactor | 해시 테이블이 얼마나 채워졌을 때 크기를 조정할지 결정하는 비율이다. |
주요메소드
put(K key, V value) | 특정 키에 값을 연결하고, 이전에 연결된 값이 있었다면 그 값을 반환한다. |
get(Object key) | 지정된 키에 연관된 값을 반환한다. 해당 키가 없으면 null을 반환한다. |
remove(Object key) | 지정된 키와 그에 연관된 값을 맵에서 제거하고 반환한다. |
containsKey(Object key) | 맵에 주어진 키가 포함되어 있는지 여부를 반환한다. |
containsValue(Object value) | 맵에 주어진 값이 하나 이상 존재하는지 여부를 반환한다. |
size() | 맵에 포함된 키-값을 쌍의 개수를 반환한다. |
isEmpty() | 맵이 비어있는지 여부를 반환한다. |
keySet() | 맵의 모든 값을 포함하는 Set을 반환한다. |
values() | 맵의 모든 값을 포함하는 Collection을 반환한다. |
entrySet() | 맵의 키-값 쌍을 포함하는 Set을 반환한다. |
clear() | 맵의 모든 키-값 쌍을 제거하여 비운다. |
사용예제
import java.util.HashMap;
import java.util.Map;
public class HashMapEx {
public static void main(String[] args) {
// HashMap 생성
Map<String, Integer> hashMap = new HashMap<>();
// 키-값 쌍 추가
hashMap.put("One", 1);
hashMap.put("Two", 2);
hashMap.put("Three", 3);
// 특정 키에 대한 값을 조회
int value = hashMap.get("Two");
System.out.println("Value for key 'Two': " + value);
// 맵의 크기 조회
int size = hashMap.size();
System.out.println("Size of the hashmap: " + size);
// 모든 키-값 쌍 출력
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 특정 키 제거
hashMap.remove("Two");
// 제거 후 크기 다시 조회
size = hashMap.size();
System.out.println("Size after removing 'Two': " + size);
}
}
SortedMap
SortedMap 인터페이스는 Map의 서브 인터페이스 이며 키의 정렬된 순서를 유지하는 맵을 나타낸다.
주요메소드
comparator() | 맵의 키를 비교하는데 사용되는 Comparator를 반환한다. natural ordering으로 정렬되는 경우에는 null을 반환한다. |
subMap(K from Key, K to Key) | 주어진 범위의 서브맵을 반환한다. fromKey는 포함되고 toKey는 포함되지 않는다. |
headMap(K toKey) | 주어진 키보다 작은 키를 갖는 서브 맵을 반환한다. |
tailMap(K fromKey) | 주어진 키보다 크거나 같은 키를 갖는 서브맵을 반환한다. |
firstKey() | 가장 작은 키를 반환한다. |
lastKey() | 가장 큰 키를 반환한다. |
TreeMap
TreeMap 클래스는 이진 검색 트리 기반의 정렬된 맵을 나타낸다. 키-값 쌍을 저장하며 키에 대한 정렬을 보장한다.
특징
- 키에 대한 정렬을 기본적으로 자동으로 수행한다. 기본 오름차순이며 Comparator를 제공하여 사용자 정의 정렬도 가능하다.
- 내부적으로는 이진 검색트리 구조를 사용하여 데이터를 저장하고, 검색, 삽입, 삭제 등의 연산이 O(log n)에 가까운 시간 복잡도를 가진다.
- 키 또는 값에 null을 허용한다. 키가 null인 경우에는 NullPointerException 예외가 발생할 수 있다.
- SortedMap 인터페이스를 구현하므로 정의된 메서드 들을 사용할 수 있다.
- subMap, headMap, tailMap 등을 사용하여 검색이나 서브맵을 생성할 수 있다.
주요메소드
put(K key, V value) | 특정 키에 값을 연결하고, 해당 키에 값이 이미 있다면 이전 값을 반환한다. |
get(Object key) | 지정된 키에 연관된 값을 반환한다. 해당 키가 없으면 null을 반환한다. |
remove(Object key) | 지정된 키와 그에 연관된 값을 맵에서 제거하고, 제거된 값을 반환한다. |
firstKey() | 가장 작은 키를 반환한다. |
lastKey() | 가장 큰 키를 반환한다. |
ceilingKey(K key) | 지정된 키와 동등하거나 바로 위에 있는 키를 반환한다. |
floorKey(K key) | 지정된 키와 똥등하거나 바로 아래에 있는 키를 반환한다. |
higherKey(K key) | 지정된 키보다 큰 키 중에서 가장 작은 키를 반환한다. |
lowerKey(K key) | 지정된 키보다 작은 키 중에서 가장 큰 키를 반환한다. |
subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) | 주어진 범위에 속하는 맵을 반환한다. |
headMap(K to key, boolean inclusive) | 주어진 키보다 작은 키들의 맵을 반환한다. |
tailMap(K fromKey, boolean inclusive) | 주어진 키보다 큰 키들의 맵을 반환한다. |
descendingMap() | 맵을 역순으로 정렬한 맵을 반환한다. |
desendingKeySet() | 맵의 키를 역순으로 정렬한 NavigableSet을 반환한다. |
poolFirstEntry() | 가장 작은 키와 그에 연관된 값을 맵에서 제거하고 반환한다. |
poolLastEntry() | 가장 큰 키와 그에 연관된 값을 맵에서 제거하고 반환한다. |
사용예제
import java.util.TreeMap;
public class TreeMapEx {
public static void main(String[] args) {
// TreeMap 생성
TreeMap<String, Integer> treeMap = new TreeMap<>();
// 키-값 쌍 추가
treeMap.put("Three", 3);
treeMap.put("One", 1);
treeMap.put("Four", 4);
treeMap.put("Two", 2);
// 정렬된 순서로 출력
for (String key : treeMap.keySet()) {
System.out.println("Key: " + key + ", Value: " + treeMap.get(key));
}
}
}
'Language > Java' 카테고리의 다른 글
[Java] Optinal 클래스 사용해보기 (0) | 2024.03.13 |
---|---|
[Java] Interface 정리(2) (0) | 2023.07.18 |
[Java] InterFace 정리(1) (0) | 2023.07.17 |
[Java] 자바 상속 정리 (0) | 2023.07.14 |
[Java] foreach문 사용하기 (0) | 2023.07.12 |