컬렉션 프레임워크
- 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 관련 인터페이스와 클래스들을 포함시켜 놓은 java.util 패키지
컬렉션(collection)
- 데이터를 한곳에 모아 저장 및 관리하는 가변 크기의 오브젝트 컨테이너
- 오브젝트를 여러 개 저장할 때
- 배열을 사용하는 경우→모든 원소의 위치 조정 필요
- 연결 리스트를 사용하는 경우→링크만 재조정 하면 됨
컬렉션 프레임워크 특징
고성능
- 연결 리스트, 트리, 해쉬 맵 등의 자료구조를 고성능으로 최적화
편의성
- 개발자가 자료구조를 구현할 필요 없음
- 인터페이스와 메서드만 잘 익히면 됨
범용성
- 제네릭을 이용해 다양한 오브젝트와 호환되도록 구현
컬렉션 프레임워크 구조
- 인터페이스와 클래스로 구성
Iterable 인터페이스
package java.lang;
public interface Iterable<T>{
Iterator<T> iterator();
}
- 반복할 수 있는 객체를 의미
- java.lang 패키지
- 반복자(Iterator)를 반환할 수 있는 객체가 되기 위해 구현
- for-each 루프를 사용할 수 있게 해주는 핵심 인터페이스
Iterator<T> iterator();
- Iterator객체를 순회할 수 있는
Iterator
반환
Iterator인터페이스
public interface Iterator<E>
- 컬렉션 원소에 접근하기 위한 반복자
- 반복처리를 할 때 유용
- 예: 연결리스트를 처음부터 차례대로 순회
- 키-값 구조의 Map컬렉션은 반복자 미제공(Map은 Iterable을 상속하고 있지 않음)
메서드 | 설명 |
---|---|
boolean hasNext() |
다음 원소의 존재 여부를 반환한다. |
E next() |
다음 원소를 반환한다. |
default void remove() |
마지막에 순회한 컬렉션의 원소를 삭제한다. |
//IteratorDemo.java
import java.util.*;
public class IteratorDemo {
public static void main(String[] args) {
Collection<String> list = Arrays.asList("A", "B", "C");
Iterator<String> iterator = list.**iterator()**;
while (iterator.**hasNext()**)
System.out.print(iterator.**next()** + ",");
System.out.println();
while (iterator.hasNext())
System.out.print(iterator.next() + ",");
System.out.println();
iterator = list.iterator();
while (iterator.hasNext())
System.out.print(iterator.next() + ",");
System.out.println();
}
}
Collection 인터페이스
interface Collection<E>
- 제네릭 타입 E가 컬렉션의 원소타입 지정
인터페이스 | 특징 | 구현 클래스 |
---|---|---|
List | 객체의 순서가 있고, 원소가 중복될 수 있다. | ArrayList, Stack, Vector, LinkedList |
Queue | 객체를 입력한 순서대로 저장하며, 원소가 중복될 수 있다. | DelayQueue, PriorityQueue, LinkedList |
Set | 객체의 순서가 없으며, 동일한 원소를 중복할 수 없다. | HashSet, TreeSet, EnumSet |
메서드 | 설명 |
---|---|
boolean add(E e) |
객체를 맨 끝에 추가한다. |
void clear() |
저장된 모든 객체를 제거한다. |
boolean contains(Object o) |
명시한 객체의 저장 여부를 조사한다. |
boolean isEmpty() |
리스트가 비어 있는지 조사한다. |
Iterator<E> iterator() |
Iterator를 반환한다. |
boolean remove(Object o) |
명시한 첫 번째 객체를 제거하고, 제거 여부를 반환한다. |
int size() |
저장된 전체 객체의 개수를 반환한다. |
T[] toArray(T[] a) |
리스트를 배열로 반환한다. |
default void forEach(Consumer<? super T>action)
- 모든 원소에 대해 action 수행
- action에 인자로 람다 표현식을 전달
default boolean removeIf(Predicate <?super E> filter)
- filter의 결과가 true이면 원소를 삭제
List 인터페이스
- 순서가 있는 오브젝트를 중복여부와 상관없이 저장하는 리스트 자료구조
- 배열과 유사하지만 크기가 가변적
- 원소를 저장하거나 읽어올 때 인덱스를 사용
- ArrayList, LinkedList, Stack, Vector 등
메서드 시그니처 | 설명 |
---|---|
void add(int index, E element) |
객체를 인덱스 위치에 추가한다. |
E get(int index) |
인덱스에 있는 객체를 반환한다. |
int indexOf(Object o) |
명시한 객체가 있는 첫 번째 인덱스를 반환한다. |
E remove(int index) |
인덱스에 있는 객체를 제거한다. |
E set(int index, E element) |
인덱스에 있는 객체와 주어진 객체를 교체한다. |
List<E> subList(int fromIndex, int toIndex) |
범위에 해당하는 객체들을 리스트로 반환한다. (from 포함, to 제외) |
static <E> List<E> of(E... elements)
- JDK9~ 팩토리 메서드
- 인자를 불변 리스트(immutable list)로 반환
- null값을 원소로 가질 수 없음
- 원소가 10개 이하로 사용하도록 오버로딩 되어있음
static <T> List<T> asList(T… a)
- Array에 정의
- Arrys to List
<T> T[] toArray(T[] a)
- 배열과 리스트 간 상호 변환 시 사용
- List에 정의
- List to Array
//ListDemo.java
import java.util.Arrays;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
String[] animals1 = {"Deer", "Tiger", "Seal", "Bear"};
List<String> animals2 = **Arrays.asList**(animals1);
animals2.**set**(1, "Parrot");
// animals2.add(0, "Wolf");
for (String s : animals2)
System.out.print(s + ", ");
System.out.println();
String[] animals3 = animals2.**toArray**(new String[0]);//리스트를 배열로 반환
for (int i = 0; i < animals3.length; i++)
System.out.print(animals3[i] + ", ");
System.out.println();
List<String> car = **List.of**("Grandeur", "Sonata", "Avante", "Genesis");
//인자를 불변 리스트로 반환
car.forEach(s -> System.out.print(s + " "));
//모든 인자에 대해 action, 인자값에는 람다표현식
// car.set(1, "Santa Fe");
// List<Object> objects = List.of("a", null);
}
}
ArrayList 클래스
ArrayList(Collection<? Extend E> c)
- 가변 크기의 동적 배열
- Vector클래스와 유사하지만 동기화된 메서드로 구현
- 즉, 멀티 스레드환경에서 안전
- 특정 인덱스의 객체를 제거하거나 삽입하면 전체가 앞/뒤로 당겨지거나 밀림
- 빈번한 객체 삭제, 삽입은 권장 ❌
//ArrayListDemo.java
import java.util.ArrayList;
import java.util.List;
public class ArrayListDemo {
public static void main(String[] args) {
List<String> list = List.**of**("Grandeur", "Sonata", "Avante", "Genesis", "Soul");
System.out.println(list.indexOf("Sonata"));
System.out.println(list.contains("Santa Fe"));
List<String> cars1 = new **ArrayList**<>(list);
cars1.**add**("Santa Fe"); // Ok
cars1.**removeIf**(c -> c.startsWith("So"));
cars1.**replaceAll**(s -> "New " + s);
cars1.**forEach**(s -> System.out.print(s + " "));
System.out.println();
cars1.**clear**(); // remove all elements
System.out.println(cars1.isEmpty());
}
}
LinkedList 클래스
- ArrayList와 달리 이웃 원소를 이중으로 연결
- ArrayList는 원소를 추가/제거할 때 인덱스 조정 필요
- LinkedList는 전후 원소의 참조값만 조정하면 ok
- 객체 삭제와 삽입이 빈번한 곳에서 ArrayJList보다 유리
//PerformanceDemo.java
import java.util.ArrayList;
import java.util.LinkedList;
public class PerformanceDemo {
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<Integer>();
LinkedList<Integer> ll = new **LinkedList**<Integer>();
long start = System.nanoTime();
for (int i = 0; i < 100000; i++)
al.add(0, i);
long end = System.nanoTime();
long duration = end - start;
System.out.println("ArrayList processing time: " + duration);
start = System.nanoTime();
for (int i = 0; i < 100000; i++)
ll.**add**(0, i);
end = System.nanoTime();
duration = end - start;
System.out.println("LinkedList processing time: " + duration);
}
}
구분 | ArrayList 클래스 | LinkedList 클래스 |
---|---|---|
구현 | 가변 크기 배열 | 이중 연결 리스트 |
초기 용량 | 10 | 0 |
get() 연산 |
빠름 | 느림 |
add() , remove() 연산 |
느림 | 빠름 |
메모리 부담 | 적음 | 많음 |
Iterator | 순방향 | 순방향, 역방향 모두 가능 |
Vector 클래스
- 동기화된 메서드로 구성돼 있어 멀티 스레드가 동시에
Vector()
메서드를 실행 불가 - 멀티 스레드 환경에서는 안전하게 객체를 추가 또는 삭제 가능
Stack 클래스
- LIFO(Last-In-First-Out) 방식으로 오브젝트 관리
- Vector의 자식 클래스
- 인덱스가 1부터 시작하는 것이 특징
메서드 | 설명 |
---|---|
boolean empty() |
스택이 비어 있는지 조사한다. |
E peek() |
스택의 최상위 원소를 제거하지 않고 엿본다. |
E pop() |
스택의 최상위 원소를 반환하며, 스택에서 제거한다. |
E push(E item) |
스택의 최상위에 원소를 추가한다. |
int search(Object o) |
주어진 원소의 인덱스 값(1부터 시작)을 반환한다. (찾지 못하면 -1 반환) |
//StackDemo.java
import java.util.Stack;
public class StackDemo {
public static void main(String[] args) {
Stack<String> s1 = new Stack<>();
s1.push("Apple");
s1.push("Banana");
s1.push("Cherry");
System.out.println(s1.peek());
System.out.println(s1.pop());
System.out.println(s1.pop());
System.out.println(s1.pop());
System.out.println();
Stack<Integer> s2 = new Stack<>();
s2.add(10);
s2.add(20);
s2.add(1, 100);
for (int value : s2)
System.out.print(value + " ");
System.out.println();
while (!s2.empty())
System.out.print(s2.pop() + " ");
}
}
Queue 인터페이스
- FIFO(First-In-First-Out)방식을 지원
- 큐의 입구, 출구를 후단(tail), 전단(head)이라고 함
- 후단에 원소를 추가, 전단에서 원소를 제거함
- 큐의 중간에 원소를 추가하거나 제거할 수는 없음
- ArrayDeque, DelayQueue, LinkedList 등
기능 | 예외를 던짐 (예외 발생 시) | null 또는 false를 반환 (예외 대신 반환) |
---|---|---|
삽입 | boolean add(E e) |
boolean offer(E e) |
삭제 | E remove() |
E poll() |
검색 | E element() |
E peek() |
//QueueDemo.java
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Queue;
public class QueueDemo {
public static void main(String[] args) {
Queue<String> q = new **LinkedList**<>();
// q.remove();
System.out.println(q.**poll**());
q.**offer**("Apple");
System.out.println("Did you add Banana? " + q.**offer**("Banana"));
try {
q.add("Cherry");
} catch (IllegalStateException e) {
}
System.out.println("Head: " + q.peek());
String head = null;
try {
head = q.**remove**();
System.out.println(head + " removed");
System.out.println("New head: " + q.**element**());
} catch (NoSuchElementException e) {
}
head = q.**poll**();
System.out.println(head + " removed");
System.out.println("New head: " + q.peek());
}
}
Set 인터페이스
public interface Set<E>
- 순서가 없으며, 중복되지 않는 오브젝트를 저장하는 자료구조
- 추가된 메서드는 없지만 중복 원소를 배제
- 인덱스가 없어 저장 순서 무시
- 객체를 중복해서 저장할 수 없고, 하나의 null만 저장할 수 있음
※ 같은 오브젝트: hashCode() 의 반환 값이 같고 equls()의 반환값이 true인 오브젝트들
static<E> Set <E> of(E... elements)
- JDK9~ 팩토리 매서드
- 인자를 받아 수정할 수 없는 Set을 생성함
HashSet
- 내부적으로 해싱을 이용한 Set구현체
- 동등 객체를 중복하지 않음
- 다른 객체라도 hashCode() 메소드의 리턴값이 같고, equals() 메소드가 true를 리턴하면 동일한 객체라고 판단하고 중복저장 ❌
- 탐색 속도가 빠름
TreeSet
- 이진탐색트리를 이용한 Set구현체
- 여러 개의 노드가 트리 형태로 연결된 구조
- 루트 노드에서 시작해 각 노드에 최대 2개의 노드를 연결 가능
- TreeSet에 객체 저장 시 부모노드의 객체와 비교해서 낮은 것은 왼쪽 자식 노드에, 높은 것은 오른쪽 자식 노드에 저장
- 데이터 정렬이 가능함
//HashSetDemo.java
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class HashSetDemo {
public static void main(String[] args) {
String[] fruits = { "Apple", "Banana", "Grape", "Watermelon"};
Set<String> h1 = new HashSet<>();
Set<String> h2 = new HashSet<>();
for (String s : fruits)
h1.**add**(s);
System.out.println(h1);
h1.**add**("Banana");
h1.**remove**("Grape");
h1.**add**(null);
System.out.println(h1);
System.out.println(h1.contains("Watermelon"));
List<String> list = Arrays.**asList**(fruits);
h2.**addAll**(list);
System.out.println(h2);
}
}
Map 인터페이스
- 키와 값의 쌍으로 구성된 오브젝트를 저장하는 자료구조
- 키와 값은 모두 오브젝트
- 키는 중복되지 않고 하나의 값에만 매핑되어 있음
- HashMap, Hashtable, TreeMap, Properies 등
- 저장된 키와 동일한 키로 값을 저장하면 새로운 값으로 대치
메서드 시그니처 | 설명 |
---|---|
void clear() |
모든 매핑을 삭제한다. |
boolean containsKey(Object key) |
주어진 키의 존재 여부를 반환한다. |
boolean containsValue(Object value) |
주어진 값의 존재 여부를 반환한다. |
Set<Map.Entry<K,V>> entrySet() |
모든 매핑을 Set 타입으로 반환한다. |
V get(Object key) |
주어진 키에 해당하는 값을 반환한다. |
boolean isEmpty() |
컬렉션이 비어 있는지 여부를 반환한다. |
Set<K> keySet() |
모든 키를 Set 타입으로 반환한다. |
V put(K key, V value) |
주어진 키-값을 저장하고 값을 반환한다. |
V remove(Object key) |
키와 일치하는 원소를 삭제하고 값을 반환한다. |
int size() |
컬렉션의 크기를 반환한다. |
Collection<V> values() |
모든 값을 Collection 타입으로 반환한다. |
Map.Entry<K, V>
- 맵의 키, 값을 조작할 때 사용
메서드 시그니처 | 설명 |
---|---|
K getKey() |
원소에 해당하는 키를 반환한다. |
V getValue() |
원소에 해당하는 값을 반환한다. |
V setValue(V value) |
원소의 값을 교체한다. |
static <K, V> Map<K,V> of(K k1, V v1)
- 수정할 수 없는 맵을 생성하는 팩토리 메서드
default void forEach(BiConsumer action)
- 맵을 순회하며 주어진 action을 수행
default void replaceAll(BiFunction function)
- 맵의 원소를 function에 따라 값을 수정
Hashtable
- 동기화된 메소드로 구성되어 있어 멀테 스레드가 동시에 Hashtable의 메소드들을 실행 불가
- 멀티 스레드 환경에서도 안전하게 객체를 추가 삭제 가능
HashMap
- 키로 사용할 객체가 hashCode() 메소드의 리턴 값이 같고 equals() 메소드가 true를 리턴하면 동일 키로 보고 중복 저장 허용하지 않음
//HashMap1Demo.java
import java.util.HashMap;
import java.util.Map;
public class HashMap1Demo {
public static void main(String[] args) {
Map<String, Integer> map =Map.**of**("Apple", 5, "Banana", 3, "Grape", 10, "Strawberry", 1);
Map<String, Integer> fruits = new **HashMap**<>(map);
System.out.println("# of fruit types: " + fruits.size());
fruits.**remove**("Banana");
System.out.println("# of fruit types: " + fruits.**size**());
fruits.**put**("Mango", 2);
System.out.println("After adding Mango: " + fruits);
fruits.**clear**();
System.out.println("# of fruit types: " + fruits.size());
}
}
Properties
- Hashtable의 자식 클래스 키와 값을 String 타입으로 제한한 컬렉션
- 주로 확장자가 .properties인 프로퍼티 파일을 읽을 때 사용
- 프로퍼티 파일은 키와 값이 = 기호로 연결된 텍스트 파일
TreeMap
- 이진 트리를 기반으로 한 Map컬렉션, 키와 값이 저장된 엔트리 저장
- 부모 키값과 비교해서 낮은 것은 왼쪽 높은 것은 오른쪽 자식 노드에 Entry 객체를 저장
Collections 클래스
- 컬렉션을 다루는 다양한 메서드 제공
- 원소 정렬, 섞기, 탐색 등의 문제를 쉽게 해결
메서드 | 설명 |
---|---|
boolean disjoint(Collection c1, Collection c2) |
두 컬렉션에 공통된 원소가 있는지 조사한다. |
boolean addAll(Collection c, E... elements) |
명시된 원소들을 컬렉션에 삽입한다. |
void copy(List dest, List src) |
리스트를 다른 리스트로 복사한다. |
void fill(List list, Object obj) |
리스트의 모든 원소를 특정 값으로 덮어쓴다. |
int frequency(Collection c, Object o) |
컬렉션에 주어진 원소의 빈도수를 반환한다. |
T max(Collection coll) |
컬렉션에서 최대값을 반환한다. |
T min(Collection coll) |
컬렉션에서 최소값을 반환한다. |
List nCopies(int n, Object o) |
주어진 객체를 주어진 횟수만큼 복사한 불변 리스트를 반환한다. |
void reverse(List list) |
리스트의 원소들을 역순으로 정렬한다. |
void swap(List list, int i, int j) |
리스트에서 주어진 위치에 있는 두 원소를 교체한다. |
void sort(List list) |
리스트를 오름차순(자연 순서)으로 정렬한다. |
void sort(List list, Comparator c) |
주어진 Comparator를 사용해 리스트를 정렬한다. |
Comparator reverseOrder() |
기본 정렬 순서를 반대로 하는 Comparator를 반환한다. |
Comparator reverseOrder(Comparator c) |
주어진 Comparator의 역순 정렬을 수행하는 Comparator를 반환한다. |
//SortDemo.java
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SortDemo {
public static void main(String[] args) {
String[] fruits = {"Grape", "Watermelon", "Apple", "Kiwi", "Mango"};
List<String> list = Arrays.asList(fruits);
Collections.**sort**(list, Collections.reverseOrder());
System.out.println(list);
Collections.**reverse**(list);
System.out.println(list);
}
}
'Java' 카테고리의 다른 글
Map.Entry (java.util) (0) | 2025.05.01 |
---|---|
Comparable (java.lang), Comparator (java.util) (1) | 2025.04.30 |
JDK, JRE, JVM (1) | 2025.04.22 |
데이터 타입 분류 - JAVA (0) | 2025.04.20 |
제어문 - JAVA (0) | 2025.04.15 |