IT

[Java] 컬렉션 프레임워크(Collection Framework)

data-cloud 2025. 1. 22. 22:06
반응형


 

☕️ 컬렉션 프레임워크(Collection Framework)란?

컬렉션 프레임워크(collection framework)란 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합을 의미한다. 컬렉션 프레임워크의 주요 인터페이스에는 List, Set, Map이 있으며 각 각의 인터페이스들은 구현체를 가지고 있다.

출처 - https://hyuntaekhong.github.io/blog/java-basic25/

 
각 각의 인터페이스의 주요 특징으로는

  • List
    - 순서가 있는 데이터 집합이다.
    - 데이터의 중복을 허용한다.

  • Set
    - 순서가 없는 데이터 집합이다.
    - 데이터의 중복을 허용하지 않는다.

  • Map
    - 키와 값의 한 쌍으로 이루어진 데이터 집합으로 순서가 없다.
    - 키의 중복은 허용하지 않고, 값의 중복은 허용한다.

 
 
 

☕️ List 인터페이스

List 인터페이스는 저장 순서를 유지해 주고, 데이터의 중복을 허용한다.
List 인터페이스를 구현하는 대표적인 클래스에는 ArraysList, LinkedList, Vector가 있다.

  • ArrayList
    - 단방향 포인터 구조로 인덱스로 접근하므로 조회할 때 유리하지만, 데이터의 삽입이나 삭제가 발생할 경우 인덱스를 조정하는 추가 작업이 필요하다.

  • LinkedList
    - 순차 접근만 가능하여 조회할 때는 불리하지만, 양방향 포인터 구조로 데이터의 삽입, 삭제에 유리하다.

  • Vector
    - ArrayList와 구현 원리와 기능적인 측면에서 동일하며, 동기화를 지원한다.

주요 메서드 설명
boolean add(E e) 주어진 객체를 맨 끝에 추가
void add(int index, E element) 주어진 인덱스에 객체를 추가
set(int index, E element) 주어진 인덱스에 저장된 객체를 주어진 객체로 변경
boolean contains(Object o) 주어진 객체가 있는지에 대한 여부를 검색
E get(int index) 주어진 인덱스에 저장된 객체를 리턴
isEmpty() 컬렉션이 비어있는지 확인
int size() 저장되어 있는 전체 객체 수를 리턴
E remove(int index) 주어진 인덱스에 저장된 객체를 삭제
void clear() 저장되어 있는 객체 모두 비우기
boolean remove(Object o) 주어진 객체 삭제

 

반응형

 

List 예제코드

 

더보기
import java.util.*;

public class ListEx {

    public static void main(String[] args) {
        /* ArrayList */
        List<String> arrayList = new ArrayList<>();
        // 요소 추가
        arrayList.add("가");
        arrayList.add("나");
        arrayList.add("다");
        System.out.println(arrayList); // [가, 나, 다]

        // 인덱스를 통한 요소 추가
        arrayList.add(0, "라");
        System.out.println(arrayList); // [라, 가, 나, 다]

        // 값 변경
        arrayList.set(0, "마");
        System.out.println(arrayList); // [마, 가, 나, 다]

        // 인덱스를 통한 요소 삭제
        arrayList.remove(0);
        System.out.println(arrayList); // [가, 나, 다]

        // 값을 통한 요소 삭제
        arrayList.remove("나");
        System.out.println(arrayList); // [가, 다]

        // 배열로 값 반환
        Object[] obj = arrayList.toArray();
        System.out.println(Arrays.toString(obj)); // [가, 다]

        // 초기화 전
        System.out.println(arrayList); // [가, 다]
        System.out.println(arrayList.size()); // 2
        System.out.println(arrayList.isEmpty()); // false

        // 초기화 후
        arrayList.clear();
        System.out.println(arrayList); // []
        System.out.println(arrayList.size()); // 0
        System.out.println(arrayList.isEmpty()); // true

        // 인덱스 및 값을 통한 요소 삭제2
        List list2 = null;
        // 인덱스로 삭제
        list2 = new ArrayList<>();
        list2.add("1");
        list2.add(2);
        list2.add(1);
        System.out.println(list2); // [1, 2, 1]
        list2.remove(1);
        System.out.println(list2); // [1, 1] : 1번째 인덱스인 2가 삭제됨.
        // 요소로 삭제
        list2 = new ArrayList<>();
        list2.add("1");
        list2.add(2);
        list2.add(1);
        System.out.println(list2); // [1, 2, 1]
        list2.remove(new Integer(1));
        System.out.println(list2); // [1, 2] : 숫자 1이 삭제됨.

        // A.retainAll(B) : A의 요소 중 B에 존재하는 요소만 남기고 삭제한다.
        List<String> listA = null;
        List<String> listB = null;
        // listA.retainAll(listB);
        listA = new ArrayList<>();
        listA.add("A"); listA.add("B"); listA.add("C"); listA.add("H");
        listB = new ArrayList<>();
        listB.add("B"); listB.add("C"); listB.add("D");
        System.out.println(listA); // [A, B, C, H]
        System.out.println(listB); // [B, C, D]
        listA.retainAll(listB);
        System.out.println(listA); // [B, C]
        System.out.println(listB); // [B, C, D]
        // listB.retainAll(listA);
        listA = new ArrayList<>();
        listA.add("A"); listA.add("B"); listA.add("C"); listA.add("H");
        listB = new ArrayList<>();
        listB.add("B"); listB.add("C"); listB.add("D");
        System.out.println(listA); // [A, B, C, H]
        System.out.println(listB); // [B, C, D]
        listB.retainAll(listA);
        System.out.println(listA); // [A, B, C, H]
        System.out.println(listB); // [B, C]

        // Arrays.asList()를 사용한 ArrayList 생성
        List<String> arraysAsList = new ArrayList(Arrays.asList("A", "B", "C", "D"));



        /* Vector - ArrayList와 유사하나 동기화 메서드로 구현되어 있어 멀티 쓰레드에 적합하다. */
        List<String> vector = new Vector<>();


        /* LinkedList - ArrayList와 유사하나 인덱스로 저장하는게 아닌 앞뒤 객체의 정보를 저장한다. */
        List<String> linkedList = new LinkedList<>();

        /*
            ArrayList와 LinkedList 성능비교
            1. ArrayList    - 검색 속도 빠름, 추가&삭제 느림(순차적 추가&삭제는 더 빠르다.)
                               * ArrayList의 요소를 순차적으로 삭제할 경우, 뒤에서부터 순차적으로 삭제한다면 배열의 복사가 발생하지 않는다.
            2. LinkedList   - 검색 속도 느림, 추가&삭제 빠름
         */
    }

}

 
 
 
 

☕️ Set 인터페이스

Set 인터페이스는 저장 순서를 유지하지 않고, 데이터 중복을 허용하지 않는다.
Set 인터페이스를 구현하는 대표적인 클래스에는 HashSet, TreeSet, LinkedHashSet이 있다.

  • HashSet
    - 가장 빠르게 접근할 수 있으나 순서를 보장하지 않는다.

  • TreeSet
    - 입력한 순서대로 값을 저장하지 않지만, 기본적으로 오름차순으로 정렬한다.

  • LinkedHashSet
    - 입력한 순서대로 값을 저장한다.

주요 메서드 설명
boolean add(E e) 주어진 객체를 저장 후 성공이면 true를 중복 객체면 false를 리턴
boolean contains(Object o) 주어진 객체가 있는지에 대한 여부를 검색
Iterator<E> iterator() 저장된 객체를 한 번씩 가져오는 반복자(Iterator)를 리턴
isEmpty() 컬렉션이 비어있는지 확인
int size() 저장되어 있는 전체 객체 수를 리턴
void clear() 저장되어 있는 객체 모두 비우기
boolean remove(Object o) 주어진 객체 삭제

 

Set 예제코드
더보기
import java.util.*;

public class SetEx {

    public static void main(String[] args) {
        /* HashSet */
        Set<String> hashSet = new HashSet<>();
        // 요소 추가
        hashSet.add("가");
        hashSet.add("나");
        hashSet.add("가"); // 중복을 허용하지 않는다.
        hashSet.add("다");
        System.out.println(hashSet); // [가, 다, 나] : HashSet은 추가한 순서대로 출력되지 않는다.

        // 요소 삭제
        hashSet.remove("다");
        System.out.println(hashSet); // [가, 나] : HashSet은 추가한 순서대로 출력되지 않는다.
        
        // 요소 확인
        System.out.println(hashSet.contains("나")); // true
        System.out.println(hashSet.contains("다")); // false

        // 모든 요소 출력
        Iterator<String> it = hashSet.iterator();
        while (it.hasNext()) {
            System.out.println(it.next()); // 저장되어있던 가, 나를 하나씩 출력
        }


        /* LinkedHashSet - HashSet과 유사하나 입력 순서가 보장된다. */
        Set<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("라");
        linkedHashSet.add("다");
        linkedHashSet.add("나");
        linkedHashSet.add("가");
        System.out.println(linkedHashSet); // [라, 다, 나, 가]


        /* TreeSet - HashSet과 유사하나 정렬 및 검색 기능이 추가되었다. */
        TreeSet<String> treeSet = new TreeSet<>();
        treeSet.add("라");
        treeSet.add("바");
        treeSet.add("나");
        treeSet.add("다");
        treeSet.add("가");
        treeSet.add("마");
        System.out.println(treeSet); // [가, 나, 다, 라, 마, 바] : 크기 순으로 출력
        System.out.println(treeSet.first()); // 가 : 원소 중 가장 작은 원소값 출력
        System.out.println(treeSet.last()); // 바 : 원소 중 가장 큰 원소값 출력

        // 데이터 꺼내기
        System.out.println(treeSet.pollFirst()); // 가
        System.out.println(treeSet.pollFirst()); // 나
        System.out.println(treeSet.pollLast()); // 바
        System.out.println(treeSet); // [다, 라, 마] : pollFirst() 또는 pollLast()를 통해 데이터를 꺼내면 저장된 원소에서 제거된다.

        // 데이터 정렬
        NavigableSet<String> navigableSet = treeSet.descendingSet();
        System.out.println(navigableSet); // [마, 라, 다]
        System.out.println(navigableSet.descendingSet()); // [다, 라, 마]

        // 부분 집합 생성
        treeSet.add("가");
        treeSet.add("나");
        treeSet.add("바");
        System.out.println(treeSet); // [가, 나, 다, 라, 마, 바]
        System.out.println(treeSet.headSet("다")); // [가, 나] : 파라미터 미만 데이터(포함x)
        System.out.println(treeSet.headSet("다", true)); // [가, 나, 다] : 파라미터 이하 데이터(포함o)
        System.out.println(treeSet.tailSet("다")); // [다, 라, 마, 바] : 파라미터 이상 데이터(포함o)
        System.out.println(treeSet.tailSet("다", false)); // [라, 마, 바] : 파리미터 초과 데이터(포함x)
        System.out.println(treeSet.subSet("나", "라")); // [나, 다]
        System.out.println(treeSet.subSet("나", true, "라", true)); // [나, 다, 라]


        // 객체 데이터 예제 - equals()와 hashCode() 오버라이딩
        Set<Person> hashSet1 = new HashSet<>();
        hashSet1.add(new Person("choi", 20));
        hashSet1.add(new Person("kim", 31));
        hashSet1.add(new Person("choi", 31));
        hashSet1.add(new Person("choi", 20));
        hashSet1.add(new Person("kim", 40));
        Iterator<Person> iterator1 = hashSet1.iterator();
        while (iterator1.hasNext()) {
            System.out.println(iterator1.next());
        }
        /*
            choi(20)
            kim(31)
            choi(31)
            kim(40)
         */


        // 객체 데이터 예제 - equals()와 hashCode() 오버라이딩 안함
        Set<Person2> hashSet2 = new HashSet<>();
        hashSet2.add(new Person2("choi", 20));
        hashSet2.add(new Person2("kim", 31));
        hashSet2.add(new Person2("choi", 31));
        hashSet2.add(new Person2("choi", 20));
        hashSet2.add(new Person2("kim", 40));
        Iterator<Person2> iterator2 = hashSet2.iterator();
        while (iterator2.hasNext()) {
            System.out.println(iterator2.next());
        }
        /*
            kim(40)
            choi(20)
            choi(31)
            kim(31)
            choi(20)
         */


        // 집합 (합집합, 교집합, 차집합)
        Set<Integer> setA = new HashSet<>();
        Set<Integer> setB = new HashSet<>();

        // 값 초기화
        setA.add(1); setA.add(2); setA.add(3); setA.add(4); setA.add(5);
        System.out.println(setA); // [1, 2, 3, 4, 5]
        setB.add(4); setB.add(5); setB.add(6); setB.add(7); setB.add(8);
        System.out.println(setB); // [4, 5, 6, 7, 8]

        // 교집합. 공통된 요소만 남기고 삭제
//        setA.retainAll(setB);
//        System.out.println(setA); // [4, 5]

        // 합집합. 모든 요소를 합함
//        setA.addAll(setB);
//        System.out.println(setA); // [1, 2, 3, 4, 5, 6, 7, 8]

        // 차집합. 공통 요소를 제거
        setA.removeAll(setB);
        System.out.println(setA); // [1, 2, 3]
    }

}

class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + "(" + age + ")";
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Person)) {
            return false;
        }

        Person p = (Person)obj;
        return this.name.equals(p.name) && this.age == p.age;
    }
}

class Person2 {
    String name;
    int age;

    Person2(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + "(" + age + ")";
    }
}

 
 
 
 

☕️ Map 인터페이스

Map 인터페이스는 키(key)와 값(value)으로 구성된 Entry 객체를 저장하는 구조이다. Map은 해싱(hashing)을 사용하기 때문에 방대한 양의 데이터를 검색하는 데 있어서 뛰어난 성능을 보인다. Map 인터페이스를 구현하는 대표적인 클래스에는 TreeMap, HashMap, Hashtable 등이 있다. 

  • TreeMap
    - 데이터를 이진 검색 트리(binary search tree)의 형태로 저장하므로 데이터의 삽입이나 삭제가 빠르다.

  • HashMap
    - 가장 많이 사용되는 클래스 중 하나이며, 해시 알고리즘(hash algorithm)을 사용하여 검색 속도가 매우 빠르다.

  • Hashtable
    - HashMap과 다르게 동기화를 보장한다.

주요 메서드 설명
V put(K Key, V value) 주어진 키와 값을 추가하여 저장되면 값을 리턴
boolean containsKey(Object Key) 주어진 키가 있는지 확인
boolean containsValue(Object value) 주어진 값이 있는지 확인
Set<Map.Entry<K,V>> entrySet() 모든 Map.Entry 객체를 Set에 담아 리턴
Set<K> keySet() 모든 키를 Set객체에 담아서 리턴
V get(Object key) 주어진 키에 있는 값을 리턴
boolean isEmpty() 컬렉션이 비어있는지 확인
int size() 저장되어 있는 전체 객체의 수를 리턴
Collection<V> values() 저장된 모든 값을 Collection에 담아서 리턴
void clear() 저장되어 있는 객체 모두 비우기
V remove(Object Key) 주어진 키와 일치하는 Map.Entry를 삭제하고 값을 리턴

 

Map 예제코드
더보기
import java.util.*;

public class MapEx {

    public static void main(String[] args) {
        /* HashMap */
        Map<Integer, String> hashMap = new HashMap<>();
        // 요소 추가
        hashMap.put(1, "가");
        hashMap.put(2, "나");
        hashMap.put(3, "다");
        hashMap.put(4, "다"); // value는 중복이 가능하다.
        hashMap.put(5, "라");
        hashMap.put(5, "마"); // key는 중복이 불가능하여 덮어쓰여진다.
        System.out.println(hashMap); // {1=가, 2=나, 3=다, 4=다, 5=마}

        // key를 통한 값 변경
        hashMap.replace(4, "라");
        System.out.println(hashMap); // {1=가, 2=나, 3=다, 4=라, 5=마}

        // key, value를 통한 값 변경
        hashMap.replace(4, "라", "마");
        hashMap.replace(5, "바", "사"); // key는 일치하지만 value가 일치하지 않아 변경되지 않는다.
        System.out.println(hashMap); // {1=가, 2=나, 3=다, 4=마, 5=마}

        // key 확인
        System.out.println(hashMap.containsKey(1)); // true
        System.out.println(hashMap.containsKey(6)); // false

        // value 확인
        System.out.println(hashMap.containsValue("가")); // true
        System.out.println(hashMap.containsValue("하")); // false

        // key를 통한 값 제거
        hashMap.remove(1);
        System.out.println(hashMap); // {2=나, 3=다, 4=마, 5=마}

        // key, value를 통한 값 제거
        hashMap.remove(4, "마");
        hashMap.remove(5, "바"); // key는 일치하지만 value가 일치하지 않아 제거되지 않는다.
        System.out.println(hashMap); // {2=나, 3=다, 5=마}

        // clear
        hashMap.clear();


        /* Hashtable - HashMap과 유사하나 동기화 메서드로 구현되어 있어 멀티 쓰레드에 적합하다. */
        Map<Integer, String> hashtable = new Hashtable<>();


        /* LinkedHashMap - HashMap과 유사하나 입력 순서가 보장된다. */
        hashMap.put(5, "가");
        hashMap.put(2, "나");
        hashMap.put(1, "다");
        System.out.println(hashMap); // {1=다, 2=나, 5=가}
        Map<Integer, String> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put(5, "가");
        linkedHashMap.put(2, "나");
        linkedHashMap.put(1, "다");
        System.out.println(linkedHashMap); // {5=가, 2=나, 1=다}


        /* TreeMap - HashMap과 유사하나 정렬 및 검색 기능이 추가되었다. */
        TreeMap<Integer, String> treeMap = new TreeMap<>();
        treeMap.put(1, "아");
        treeMap.put(2, "나");
        treeMap.put(3, "자");
        treeMap.put(4, "가");
        treeMap.put(5, "하");
        System.out.println(treeMap); // {1=아, 2=나, 3=자, 4=가, 5=하}

        // 데이터 검색
        System.out.println(treeMap.firstKey()); // 1 : key중 가장 최솟값
        System.out.println(treeMap.lastKey()); // 5 : key중 가장 최댓값
        System.out.println(treeMap.firstEntry()); // 1=아 : key중 가장 최솟값인 쌍
        System.out.println(treeMap.lastEntry()); // 5=하 : key중 가장 최댓값인 쌍

        // 정렬
        System.out.println(treeMap.descendingMap()); // key 기준 내림차순으로 정렬된 쌍
        System.out.println(treeMap.descendingKeySet()); // key 기준 내림차순으로 정렬된 key값

        // 부분 집합 생성
        System.out.println(treeMap.headMap(3)); // {1=아, 2=나}
        System.out.println(treeMap.headMap(3, true)); // {1=아, 2=나, 3=자}
        System.out.println(treeMap.headMap(3, false)); // {1=아, 2=나}
        System.out.println(treeMap.tailMap(3)); // {3=자, 4=가, 5=하}
        System.out.println(treeMap.tailMap(3, true)); // {3=자, 4=가, 5=하}
        System.out.println(treeMap.tailMap(3, false)); // {4=가, 5=하}

        /*
            선언과 동시에 초기화
            - 이중 중괄호 구문을 사용하여 구현할 수 있으나,
              익명의 추가 클래스를 생성하기 때문에 메모리 누수 문제가 발생할 수 있다.
        */
        Map<String, String> initMap = new HashMap() {
            {
                put("choi", "10");
                put("choi", "31");
                put("kim", "20");
                put("lee", "40");
            }
        };
        System.out.println(initMap); // {choi=31, lee=40, kim=20}
    }

}

 
 
 
 
 

References.

1. Inpa - Java Collections Framework 종류
2. TCPschool - 컬렉션 프레임워크의 개념
3. 코딩팩토리 - [Java] 자바 컬렉션 프레임워크(List, Set, Map) 총정리
4. kai6666.log - [Java] 컬렉션 프레임워크 (Collection Framework)

 

반응형