Collection 프레임워크

컬렉션 프레임워크

  • 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 관련 인터페이스와 클래스들을 포함시켜 놓은 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