컬렉션 프레임워크

2025. 4. 30. 15:42·Backend/JAVA
728x90

자바는 널리 알려진 자료구조를 바탕으로, 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 관련된 인터페이스와 클래스들을 `java.util` 패키지에 포함시켜 놓음

👉 이를 총칭하여 컬렉션 프레임워크라고 부름

주요 인터페이스

  • List와 Set은 객체를 추가, 삭제, 검색하는 방법에 있어서 공통점이 있기에
    공통된 메소드만 따로 모아 Collection 인터페이스로 정의 & 상속
  • Map은 키와 값을 하나의 쌍으로 묶어서 관리하는 구조로 List와 Set 과는 사용방법이 다름
❓ 인터페이스로 구현한 이유
처음에는 공유 코드가 없어서 인터페이스로 설계 했으나,
시간이 흐르며 공통 기능이 필요해졌고 이를 해결하기 위해 `default` 메서드가 도입 됨
인터페이스 분류 특징 구현 클래스
Collection List 순서를 유지하고 저장
중복 저장 가능
ArrayList, Vector, LinkedList
Set 순서 유지x
중복 저장 불가
HashSet, TreeSet
Map 키와 값으로 구성된 엔트리 저장 HashMap, HashTable, TreeMap, Properties

List 컬렉션

List 컬렉션은 객체를 `인덱스`로 관리하므로, 객체를 저장하면 인덱스가 부여됨.

인덱스를 이용하여 객체 검색, 삭제 기능 제공

공통 메소드

기능 메소드 설명
객체 추가 boolean add (E e) 주어진 객체 맨 끝에 추가
void add (int index. E e) 주어진 인덱스에 객체를 추가
set (int index, E e) 주어진 인덱스의 객체를 새로운 객체로 바꿈
객체 검색 boolean contains (Object o) 주어진 객체가 저장되어 있는지 여부
E get (int index) 주어진 인덱스에 저장된 객체 리턴
int size() 저장되어 있는 전체 객체 수 리턴
객체 삭제 void clear() 저장된 모든 객체 삭제
E remove(int index) 주어진 인덱스에 저장된 객체를 삭제
boolean remove(Object o) 주어진 객체를 삭제

ArrayList

  • List 컬렉션에서 가장 많이 사용하는 컬렉션
  • ArrayList에 객체를 추가하면, 내부 배열에 객체가 저장됨
  • 배열과 달리 제한 없이 객체를 추가할 수 있다는 것

객체 자체를 저장하는 게 아닌, 객체의 `번지`를 저장

동일한 객체를 저장할 수 있는데, 이 경우에는 동일한 번지가 저장됨

List<E> list = new ArrayList<E>();	// E에 지정된 타입의 객체만 저장
List<E> list = new ArrayList<>();	// E에 지정된 타입의 객체만 저장
List list = new ArrayList();	// 모든 타입의 객체 저장

ArrayList 컬렉션에 객체를 추가하면, 인덱스 0번부터 차례대로 저장

특정 인덱스의 객체를 제거하면, 바로 뒤 인덱스부터 마지막 인덱스까지 모두 앞으로 1씩 당겨짐

∴ 빈번한 삭제/삽입이 일어나는 곳에서는 ArrayList 사용을 지양해야 함

LinkedList

 ArrayList와 사용방법이 동일하나, 내부 구조가 완전히 다름

LinkedList는 인접 객체를 체인처럼 연결해서 관리

LinkedList

특정 위치에 객체 삽입 / 삭제 시 바로 앞뒤 링크만 변경하면 됨

빈번한 삽입 삭제가 일어나는 곳에서 ArrayList보다 좋은 성능을 냄


Set 컬렉션

List 컬렉션과 달리, Set 컬렉션은 저장 순서가 유지되지 않음

객체의 중복 저장이 안 되며, 하나의 null만 저장 가능

인덱스로 관리하지 않으므로, 인덱스를 매개값으로 갖는 메소드는 없음

공통 메소드

기능 메소드 설명
객체 추가 boolean add (E e) 주어진 객체를 성공적으로 저장하면 true
중복 객체가 있는 경우 false
객체 검색 boolean contains (Object o) 주어진 객체가 저장되어 있는지 여부
isEmpty() 컬렉션이 비어 있는지 조사
`Iterator<E> iterator()` 저장된 객체를 한 번씩 가져오는 반복자 리턴
객체 삭제 void clear() 저장된 모든 객체 삭제
boolean remove(Object o) 주어진 객체를 삭제

HashSet

Set 컬렉션 중에서 가장 많이 사용되는 HashSet

Set<E> set = new HashSet<E>();	// E에 지정된 타입의 객체만 저장
Set<E> set = new HashSet<>();	// E에 지정된 타입의 객체만 저장
Set set = new HashSet();	// 모든 타입의 객체 저장

HashSet은 동일한 객체는 중복 저장하지 않음

❓ 동일하다?
동등 객체를 의미함
`hashCode()` 메소드의 리턴값이 같고, `equals()` 메소드가 true를 리턴하면 동일한 객체라고 판단

동등객체 판단

사용자 지정 동등 객체 판단 👇🏻

더보기

상황: 이름과 나이가 동일할 경우 Member 객체를 HashSet에 중복 저장 하지않는다.

public class Member{
	public String name;
    public int age;
    
    public Member(String name, int age){
    	this.name = name;
        this.age = age;
    }
    
    @Override
    public int hashCode(){
    	return name.hashCode()+age;
    }
    
    @Override
    public boolean equals(Object obj){
    	if(obj instanceof Member target){
        	return target.name.equals(name) && (target.age==age);
        }else{
        	return false;
        }
    }
}

Set 컬렉션은 인덱스로 객체를 검색해서 가져오는 메소드가 없음
∴ 객체를 한 개씩 반복해서 가져와야 함

for문을 이용해 가져오기

Set<E> set = new HashSet<>();
for(E e: set){
	...
}

iterator() 메소드 이용

Set<E> set = new HashSet<>();
Iterator<E> iter = set.iterator();

while(iter.hasNext()){
	E e= iter.next();
}
return 타입 메소드 명 설명
boolean hasNext() 가져올 객체가 있으면 true, 없으면 false
E next() 컬렉션에서 하나의 객체 가져옴
void remove() next()로 가져온 객체를 Set에서 제거

 


Map 컬렉션

Map 컬렉션은 `key`와 `value`로 구성된 `엔트리` 객체를 저장

키는 중복 저장X, 값 중복저장O

기존에 저장된 키와 동일한 키로 값을 저장하면, 기존 값이 새로운 값으로 대치됨

여기서 키와 값은 모두 객체임

공통 메소드

기능 return 타입 메소드  설명
객체 추가 V put(K key, V value) 주어진 키와 값을 추가, 저장 되면 값 리턴
객체 검색 boolean containsKey(Object key) 주어진 키가 있는지 여부
boolean containsValue(Object value) 주어진 값이 있는지 여부
Set<Map.Entry<K,V>>  entrySet() 키와 값의 쌍으로 구성된 모든 Map.Entry 객체를
Set에 담아서 return
V get(Object key) 주어진 키의 값 리턴
boolean isEmpty() 컬렉션이 비어있는지 여부
Set<K> keySet() 모든 키를 Set 객체에 담아서 return
int  size() 저장된 키의 총 수 리턴
Collection<V> values() 저장된 모든 값 Collection에 담아서 리턴
객체 삭제 void clear() 모든 Map.Entry 삭제
V remove(Object key) 주어진 키와 일치하는 Map.Entry 삭제,
삭제되면 값 return 
put 메소드 사용 시, 이전 값 (또는 null)이 반환됨

HashMap

키로 사용할 객체가 hashCode() 메소드의 리턴 값이 같고, equals() 메소드가 true를 반환할 경우,
동일 키로 보고 중복 저장 허용X

Map<K, V> map = new HashMap<>(); 

Map<String, Integer> map = new HashMap<String, Integer>(); 
Map<String, Integer> map = new HashMap<>(); 
Map map = new HashMap(); // 모든 타입 키 & 객체 저장, but 거의 없음

Properties

  • Properties는 키와 값을 `String` 타입으로 제한한 컬렉션
  • 주로 확장자가 `.properties`인 프로퍼티 파일을 읽을 때 사용

검색 기능을 강화한 컬렉션

컬렉션 프레임워크는 검색 기능을 강화한 TreeSet, TreeMap을 제공

TreeSet

이진 트리를 기반으로 한 Set 컬렉션

❓ 이진 트리

여러 개의 노드가 트리 형태로 연결된 구조로, 루트 노드라 불리는 하나의 노드에서 시작해
각 노드에 최대 2개의 노드를 연결할 수 있는 구조

TreeSet

TreeSet에 객체를 저장하면 자동으로 정렬 됨.

부모노드의 객체와 비교하여 낮은 것은 왼쪽 자식에, 높은 것은 오른쪽 자식 노드에 저장

TreeSet<E> set = new TreeSet<E>();
TreeSet<E> set = new TreeSet<>();

TreeSet 타입으로 대입한 이유는 검색 관련 메소드가 TreeSet에만 정의 돼 있기 때문임

TreeSet이 가진 검색 관련 메소드

return 타입 메소드 설명
E first() 제일 낮은 객체 리턴
last() 제일 높은 객체 리턴
lower(E e) 주어진 객체보다 바로 아래 객체 리턴
higher(E e) 주어진 객체보다 바로 위 객체 리턴
floor(E e) 주어진 객체와 동등 객체 리턴, 없으면 바로 아래 객체 리턴
ceiling(E e) 주어진 객체와 동등 객체 리턴,
없으면 바로 위 객체 리턴
pollFirst() 제일 낮은 객체 꺼내오고 제거
pollLast() 제일 높은 객체 꺼내오고 제거
Iterator<E> descendingIterator() 내림차순으로 정렬된 Iterator 리턴
NavigableSet<E> descendingSet() 내림차순으로 정렬된 NavigableSet 리턴
headSet(
E toElement,
boolean inclusive
)
주어진 객체보다 낮은 객체들을 NavigableSet 리턴,
주어진 객체 포함 여부는 inclusive
tailSet(
E toElement,
boolean inclusive
)
주어진 객체보다 높은 객체들을 NavigableSet 리턴,
주어진 객체 포함 여부는 inclusive
subSet(
E fromElement,
boolean fromInclusive,
E toElement, 
boolean toInclusive
)
시작과 끝으로 주어진 객체 사이의 객체들을 NavigableSet 리턴,
주어진 객체 포함 여부는 inclusive

TreeMap

  • 이진 트리를 기반으로 한 Map 컬렉션
  • TreeMap에 엔트리를 저장하면 키를 기준으로 자동 정렬
TreeMap<K, V> map = new TreeMap<K, V>();
TreeMap<K, V> map = new TreeMap<>();

TreeSet과 마찬가지로 검색 관련 메소드가 TreeMap에만 정의돼 있음

return 타입 메소드 설명
Map.Entry<K, V> firstEntry() 제일 낮은 Map.Entry 리턴
lastEntry() 제일 높은 Map.Entry 리턴
lowerEntry(K key) 주어진 키보다 바로 아래 Map.Entry 리턴
higherEntry(K key) 주어진 키보다 바로 위 Map.Entry 리턴
floorEntry(K key) 주어진 키와 동등 키의 Map.Entry 리턴, 없으면 바로 아래 Map.Entry 리턴
ceilingEntry(K key) 주어진 키와 동등 키의 Map.Entry 리턴,
없으면 바로 위 Map.Entry 리턴
pollFirstEntry() 제일 낮은 Map.Entry 꺼내오고 제거
pollLastEntry() 제일 높은 Map.Entry 꺼내오고 제거
NavigableSet<K> descendingKeyset() 내림차순으로 정렬된 키의 NavigableSet 리턴
NavigableMap<K, V> descendingMap() 내림차순으로 정렬된 Map.Entry의 NavigableMap 리턴
headMap(
K toKey,
boolean inclusive
)
주어진 키보다 낮은 Map.Entry들을 NavigableMap 리턴,
주어진 키의 Map.Entry 포함 여부는 inclusive
tailMap(
K fromKey,
boolean inclusive
)
주어진 키보다 높은 Map.Entry들을 NavigableMap 리턴,
주어진 키의 Map.Entry 포함 여부는 inclusive
subMap(
K fromKey,
boolean fromInclusive,
K toKey,
boolean toInclusive
)
시작과 끝으로 주어진 키 사이의 Map.Entry 들을 NavigableMap 컬렉션으로 반환 주어진 키의 Map.Entry 포함 여부는 inclusive

동기화된 컬렉션

컬렉션 프레임워크의 대부분 클래스는 `싱글 스레드` 환경에서 사용할 수 있도록 설계
∴ 여러 스레드가 동시에 컬렉션에 접근한다면 의도치 않게 요소가 변경될 수 있는 불안전한 상태임

Vector와 HashTable은 동기화 된 메소드로 구성돼 있기 때문에 멀티 스레드 환경에서 안전하게 요소를 처리할 수 있지만,

ArrayList와 HashSet, HashMap은 멀티스레드 환경에서 안전하지 않음

📌 Vector와 HashTable의 사용은 지양!

초기 Java(1.0) 클래스로 이후 등장한 ArrayList, HashSet & HashMap이 성능면에서 효율적임
모든 메서드에 동기화 처리가 돼있어서 안전하지만 성능이 많이 떨어진다.

경우에 따라 멀티 스레드 환경에서 사용하고 싶은 경우, `synchronizedxxx()` 메소드 사용

return 타입 메소드 설명
List<T> synchronizedList(List<T> list) List를 동기화된 List로 리턴
Map<K, V> synchronizedMap(Map<K, V> m) Map를 동기화된 Map으로 리턴
Set<T> synchronizedSet(Set<T> s) Set을 동기화된 Set으로 리턴

이 메소드들은 매개값으로 비동기화된 컬렉션을 대입하면 동기화된 컬렉션 리턴

 


수정할 수 없는 컬렉션

  • 요소를 추가, 삭제할 수 없는 컬렉션
  • 컬렉션 생성 시 저장된 요소를 변경하고 싶지 않을 때 유용

생성 방법

  1. List. Set, Map 인터페이스의 정적 메소드, `of()` 사용
  2. List. Set, Map 인터페이스의 정적 메소드, `copyOf()` 사용
  3. 배열로부터 수정할 수 없는 List 컬렉션 생성

of() 

List<E> immutableList = List.of(E... elements);
Set<E> immutableSet = Set.of(E... elements);
Map<E> immutableMap = Map.of(K k1, V v1, K k2, V v2, ... );

copyOf()

기존 컬렉션을 복사하여 수정할 수 없는 컬렉션 만듦

List<E> immutableList = List.copyOf(Collection<E> coll);
Set<E> immutableSet = Set.copyOf(Collection<E> coll);
Map<E> immutableMap = Map.copyOf(Map<K, V> map);

배열 → 리스트

  • 삽입, 삭제가 불가능한 List 반환
  • `asList()` 메소드 사용
  • 만일, 가변 리스트로 변경하고 싶은 경우 `new ArrayList(Arrays.asList(arr));`로 변경
String [] arr = {"A", "B", "C"};
List<String> immutableList = Arrays.asList(arr);

리스트 → 배열

`toArray()` 메소드 사용

Integer [] arr = list.toArray(new Integer[0]); // Integer
int [] arr2 = list.stream().mapToInt(Integer::intValue).toArray(); // int

 

728x90
'Backend/JAVA' 카테고리의 다른 글
  • JDBC 프로젝트 생성
  • JDBC
  • 추상 클래스 & 봉인 클래스
  • 상속 관계에서 타입 변환의 이유와 사용 목적
0woy
0woy
Algorithm, CS, Web 등 배운 내용을 기록합니다.
  • 0woy
    0woy dev
    0woy
  • 전체
    오늘
    어제
  • 🌐 LANGUAGE
    • 분류 전체보기 (80)
      • Backend (21)
        • JAVA (7)
        • DB (11)
        • Spring (1)
        • Spring Security (2)
      • Computer Science (22)
        • 네트워크 (9)
        • 운영체제 (5)
        • 보안 (7)
      • Frontend (15)
        • HTML5 (1)
        • CSS (1)
        • JS (4)
        • Vue 3 (9)
      • PS (16)
        • LeetCode (2)
        • Baekjoon (1)
        • Programmers (1)
        • 알고리즘 (12)
      • Dev Trivia (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    javascript
    dfs
    JDBC
    shortestpath
    가용성
    RDB
    그래프
    Graph
    DP
    Filter
    속성
    PreparedStatement
    Props
    트리
    JS
    security
    select
    대칭키
    BFS
    Spring
    java
    tcp
    leetcode
    Vue3
    set
    비밀키
    CA
    function
    공개키
    https
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
0woy
컬렉션 프레임워크
상단으로

티스토리툴바