-
장점
-
Collection Framework의 종류
-
Iterable 인터페이스
-
Collcetion 인터페이스
-
1. List 인터페이스
-
1.1 ArrayList 클래스
-
1.2 Vector 클래스
-
1.3 Stack 클래스
-
2. Queue 인터페이스
-
2.1 PriorityQueue 클래스
-
3. Deque 인터페이스
-
3.1 ArrayDeque 클래스 -> 큐, Stack 대신 사용
-
3.2 LinkedList 클래스
-
4. Set 인터페이스
-
4.1 HashSet 클래스
-
4.2 LinkedHashSet 클래스
-
4.3 TreeSet 클래스
-
5. Map 인터페이스
-
5.1 HashTable 클래스
-
5.2 HashMap 클래스
-
5.3 LinkedHashMap 클래스
-
5.4 TreeMap 클래스
-
5.5 Preperties 클래스
-
정리
C언어에서 LinkedList라는 자료구조를 사용하려면 직접 구현해야함 → 자바는 JCF에서 만들어놓은 클래스를 사용하면 됨.
💡 직접 구현하는 것과 JCF 사용하는 것 중 무엇이 좋은가?
만들어 놓은데는 다 이유가 있다..
알고리즘의 속도와 안정성에 있어 자바 언어 개발진들이 수십년에 걸쳐 JVM에 최적화시켜 개량해왔으니 우리는 그걸 가져다 쓰면 된다.
장점
- 인터페이스와 다형성을 이용한 객체지향적 설계를 통해 표준화 되어 있기에, 사용법을 익히기에도 편리하고 재사용성이 높다
- 데이터 구조 및 알고리즘의 고성능 구현을 제공하여 프로그램의 성능과 품질을 향상
- 관련없는 API 산의 상호 운용성을 제공 (상위 인터페이스 타입을 업캐스팅하여 사용) → 인터페이스 중심으로 사용 → 객체지향적
- 이미 구현되어 있는 API를 제공하므로 새로운 API를 익히고 설계하는 시간이 줄어든다
- 소프트웨어 재사용을 촉진. 만일 자바에서 지원하지 않는 새로운 자료구조가 필요하다면, 컬렉션들을 재활용하여 조합하여 새로운 알고리즘을 만들어낼 수 있다.
Collcetion Framework에 저장할 수 있는 데이터는 오로지 객체 뿐.
primitive타입은 적재하지 못함. Wrapper 타입(기본 타입을 객체 타입으로 만들어주는 객체)으로 변환하도록 Boxing 과정을 거쳐야함.
Collection Framework의 종류

컬렉션 프레임워크는 크게 2가지로 나뉨
- Collection 인터페이스
- List와 Set 인터페이스를 구현한 컬렉션 클래스들은 공통부분이 많기 때문에, 공통된 부분을 모아둔 Collcetion 인터페이스에 상속되어 있다. → List, Set에서 사용하는 공통 메서드는 Collection인터페이스를 불러와 사용할 수 있다는 말
- Map 인터페이스
- Map 인터페이스: 컬렉션들은 두개의 데이터를 묶어 한쌍으로 다루기 때문에 Collcetion 인터페이스와 따로 분리되어 있다.
💡 Vector, Stack, Hashtable, Properites와 같은 클래스들은 컬렉션 프레임워크가 만들어지기 이전부터 존재하던 것이여서 컬렉션 프레임워크의 명명법을 따르지 않는다.
( … List, …Set, …Map) 이런 것들은 이전 java 버전과의 호환을 위해 남겨진 것으로 가급적 사용하지 않는 것이 좋다.
Iterable 인터페이스
컬렉션 인터페이스들의 가장 최상위 인터페이스
자료 순회할 때 이터레이터(Iterator) 객체를 다루는데, 이 이터레이터 객체를 관리하는 인터페이스이다.
- `default void forEach(Consumer<? super T> action)` : 함수형 프로그래밍 전용 루프 메서드
- `Iterator<T> iterator()`: 컬렉션에서 이터레이터를 구현할 때 사용
- `default Spliterator<T> splierator()`: 파이프라이닝 관련 메소드
💡Spliterator
Java 8 에 도입된 Spliterator 인터페이스는 시퀀스를 탐색하고 분할할 수 있다.
특히 병렬 Streams의 기본유틸리티이다.
-> 병렬 작업할 때 사용하는 메서드라고 생각하면 될 듯하다
💡Map 인터페이스에는 iterable 인터페이스를 상속받지 않음.
따라서 Map 컬렉션을 순회하려면 Stream을 사용하거나 간접적으로 키를 Collcetion으로 변환하여 루프문으로 순회하는 식으로 이용
Collcetion 인터페이스
List, Set, Queue에 상속을 하는 실질적인 최상위 컬렉션 타입
Collcetion을 구현한 객체를 업캐스팅하여 해당 자료구조에 자료를 삽입하거나 삭제, 탐색 기능을 할 수 있다.
개인적으로 많이 사용한 메서드들만 정리하겠다.
추가
boolean add(Object o)
boolean addAll(Collection c)
컬렉션에 객체가 있는지 확인
boolean containse(Object o)
boolean containsAll(Collcetion c)
삭제
boolean remove(Object o)
boolean removeAll(Collection c)
컬렉션 비우기
void clear()
동일한 컬렉션인지 비교
boolean equals(Object o)
컬렉션이 비었는지 확인
boolean isEmpty()
컬렉션 사이즈 반환
int size()
컬렉션 -> 배열
Object[] toArray()
배열에 컬렉션 객체 저장
Object[] toArray(Object[] a)
JDK 1.8 부터 함수형 프로그래밍을 위해 parallelStream, removeIf, stream, forEach 디폴트(default)메서드가 추가됨
컬렉션 인터페이스 메서드에서 get()이 없는 이유
각 컬렉션 자료형마다 구현하는 자료구조가 제각각이기 때문에 최상위 타입으로 조회하기 까다롭기 때문
->
1. List 인터페이스

- 저장 순서가 유지되는 컬렉션을 구현하는데 사용
- 같은 요소의 중복 저장 허용
- index로 요소에 접근
- 요소 사이에 빈공간 허용하지 않음 -> 삽입/삭제 시 배열이동이 일어남
💡리스트와 배열의 차이
리스트: 자료형의 크기가 가변
배열: 자료형 크기가 불변
추가
void add(int idx, Object ele)
boolean add(int idx, Collection c)
삭제
Object remove(int idx)
조회
Object get(int idx)
지정된 위치에 객체 저장
Object set(int idx, Object ele)
지정된 객체의 위치 반환
int indexOf(Object o) //순방향
int lastIndexOf(Object o) // 역방향
지정된 범위에 있는 객체 반환(슬라이스)
List subList(int fromIdx, int toIdx)
지정된 비교자(comparator)로 리스트 정렬
void sort(Comparator c)
1.1 ArrayList 클래스
- 배열을 이요하여 만든 리스트
- 데이터의 저장순서가 유지되고 중복을 허용
- 길이 가변
- 단방향 포인터 구조로 자료에 대한 순차적인 접근에 강점이 있어 조회가 빠르다
- 삭제 / 삽입이 느리다, 순차적으로 추가 / 삭제 하는 경우에 가장 빠르다.
1.2 Vector 클래스
ArrayList의 구형 버전(내부 구성이 거의 비슷)
ArrayList와의 차이는 모든 메서드가 동기화되어 있어 Thread-Safe하다는 점.
Vector는 구버전 자바와 호환성을 위해 남겨둔 것으로 잘 사용하지 않음.
만일 컬렉션에 동기화가 필요하다면 `Collcetions.synchronizedList()` 메서드를 이용해 ArrayList를 동기화 처리하여 사용
1.3 Stack 클래스
- LIFO(후입선출)
- 들어올 때는 push, 나갈때는 pop
- Stack은 Vector를 상속하므로 문제점이 많아 잘 안쓰임. -> ArrayDeque 사용
2. Queue 인터페이스

- FIFO(선입선출)
삽입
boolean add(Object o) //저장공간 부족 시 illegalStaeException
boolean offer(Obejct o)
삭제
Object remove() //비어있을 경우 NoSuchElementException
Object poll()
조회
Object element() //비어있을 경우 NoSuchElementException
Object peek() //비어있을 경우 null
2.1 PriorityQueue 클래스
- 우선순위 큐
- 우선순위 큐에 저장할 객체는 필수적으로 Comparable 인터페이스를 구현해야함. `compareTo()` 메서드 로직에 따라 자료 객체의 우선순위를 결정하는 식으로 동작되기 때문
- 저장공간을 배열로 사용하고, 각 요소를 힙(heap) 형태로 저장
- null 저장 불가능
// 우선순위 큐에 저장할 객체는 필수적으로 Comparable를 구현
class Student implements Comparable<Student> {
String name; // 학생 이름
int priority; // 우선순위 값
public Student(String name, int priority) {
this.name = name;
this.priority = priority;
}
@Override
public int compareTo(Student user) {
// Student의 priority 필드값을 비교하여 우선순위를 결정하여 정렬
if (this.priority < user.priority) {
return -1;
} else if (this.priority == user.priority) {
return 0;
} else {
return 1;
}
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", priority=" + priority +
'}';
}
}
public static void main(String[] args) {
// 오름차순 우선순위 큐
Queue<Student> priorityQueue = new PriorityQueue<>();
priorityQueue.add(new Student("주몽", 5));
priorityQueue.add(new Student("세종", 9));
priorityQueue.add(new Student("홍길동", 1));
priorityQueue.add(new Student("임꺽정", 2));
// 우선순위 대로 정렬되어 있음
System.out.println(priorityQueue);
// [Student{name='홍길동', priority=1}, Student{name='임꺽정', priority=2}, Student{name='주몽', priority=5}, Student{name='세종', priority=9}]
// 우선순위가 가장 높은 값을 참조
System.out.println(priorityQueue.peek()); // Student{name='홍길동', priority=1}
// 차례대로 꺼내기
System.out.println(priorityQueue.poll()); // Student{name='홍길동', priority=1}
System.out.println(priorityQueue.poll()); // Student{name='임꺽정', priority=2}
System.out.println(priorityQueue.poll()); // Student{name='주몽', priority=5}
System.out.println(priorityQueue.poll()); // Student{name='세종', priority=9}
}
3. Deque 인터페이스
- Deque(Double-Ended Queue)는 양쪽으로 넣고 빼는 것이 가능한 큐
- Deque -> Queue
- ArrayDeque, LinkedList -> Deque
3.1 ArrayDeque 클래스 -> 큐, Stack 대신 사용

- 스택으로 사용할 때 Stack 클래스보다 빠르며, 대기열로 사용할 때는 LinkedList 보다 빠르다.
- 사이즈에 제한이 없음
- null 저장 안됨
Deque | Queue | Stack |
offerLast() | offer() | push() |
pollLast() | pop() | |
pollFirst() | poll() | |
peekFirst() | peek() | |
peekLast() | peek() |
3.2 LinkedList 클래스
- LinkedList는 List 인터페이스와 Queue 인터페이스를 동시에 상속받고 있기 때문에, 스택/큐 로서도 응용이 가능하다.
- LinkedList 클래스에 큐 동작과 관련된 메서드를 지원한다.
- 노드(객체)를 연결하여 리스트처럼 만든 컬렉션(배열아님)
- 데이터의 중간 삽입, 삭제가 빈번할 경우 빠른 성능을 보장
- 임의의 요소에 대한 접근 성능은 좋지 않음
- 자바의 LinkedList는 Doubly LinkedList(양방향 포인터 구조)로 이루어져 있다.
- LinkedList는 리스트 용도 이외에도, 스택, 큐, 트리 등의 자료구조의 근간이 된다.
Queue<String> linkedList = new LinkedList<>(); // Queue 타입으로 받음
linkedList.offer("Hello");
linkedList.offer("World");
linkedList.offer("Power");
linkedList.poll(); // "Hello" - 선입선출
System.out.println(linkedList); // [World, Power]
💡 LinkedList 를 큐로 사용하는 이유
큐는 데이터를 꺼낼 때 항상 첫번째 저장된 데이터를 삭제하므로, ArrayList와 같은 배열 기반의 컬렉션 클래스를 사용한다면, 데이터를 꺼낼때마다 빈 공간이 생긴다.
List는 빈공간을 허용하지 않으므로 빈 공간을 채우기 위해 데이터의 이동 & 복사가 발생하므로 비효율적이다.
이런 이유로 데이터의 추가 / 삭제가 용이한 LinkedList로 큐를 구현하는 것이 적합
4. Set 인터페이스

- 데이터의 중복을 허용하지 않고 순서를 유지하지 않는 데이터 집합 리스트
- 순서 자체가 없으므로 인덱스로 객체를 검색해서 가져오는 get(index) 메서드가 존재하지 않음
- 중복 저장 불가능하고 Null값도 하나만 저장할 수 있다
삽입
boolean add(E e)
삭제
boolean remove(Object o)
- `boolean contains(Object o)`: 주어진 객체가 저장되어 있는지 리턴
- `Iterator<E> iterator()`: 저장된 객체를 한번씩 가져오는 iterator를 리턴
- `isEmpty()`: 컬렉션이 비어있는지 조사
- `int size()`: 저장되어 있는 전체 객체수를 리턴
- `void clear()`: 저장된 모든 객체를 삭제
4.1 HashSet 클래스

- 배열과 연결 노드를 결합한 자료구조 형태
- 가장 빠른 임의 검색 속도를 가진다
- 추가, 삭제, 검색, 접근성이 모두 뛰어남
- 대신 순서를 전혀 예측할 수 없다.
4.2 LinkedHashSet 클래스
- 순서를 가지는 Set 자료
- 추가된 순서 또는 가장 최근에 접근한 순서대로 접근 가능
- 만일 중복을 제거하는 동시에 순서를 유지하고 싶다면, HashSet 대신 LinkedHashSet을 사용
4.3 TreeSet 클래스
- 이진 검색 트리(binary search tree) 자료구조의 형태로 데이터를 저장
- 중복을 허용하지 않고, 순서를 가지지 않는다
- 대신 데이터를 정렬하여 저장하고 있다는 특징이다.
- 정렬, 검색, 범위 검색에 높은 성능을 뽐낸다

5. Map 인터페이스

- 키와 값의 쌍으로 연관지어 이루어진 데이터의 집합
- 값은 중복되서 저장될 수 있지만, 키는 해당 Map에서 고유해야함
- 만일 기존 저장된 데이터와 중복된 키와 값을 저장하면 기존의 값은 없어지고 마지막에 저장된 값이 남게 된다
- 저장 순서가 유지 되지 않는다.
조회
Object get(Object key)
삽입
void put(Object key, Object value)
void putAll(Map t)
삭제
Object remove(Object key)
`void clear()`: 모든 객체 삭제
`boolean containsKey(Object key)`: 지정된 key 객체와 일치하는 객체가 있는지 확인
`boolean containsValue(Object value)`: 지정된 value객체와 일치하는 객체가 있는지 확인
`Set entrySet()`: Map에 저장된 key-value쌍을 Map.Entry 타입의 객체로 저장한 Set을 반환
`boolean equals(Object o)`: 동일한 Map인지 비교
`int size()`: 크기 반환
`boolean isEmpty()`: Map이 비었는지 확인
`Set keySet()`: Map에 저장된 모든 key객체를 반환
`Collection values()`: Map에 저장된 모든 value객체를 반환
💡 Map에 저장되는 key-value 쌍의 노드 살펴보기
노드는 Map.Entry 인터페이스를 구현하고 있다.
Map.Entry 인터페이스는 Map 인터페이스 안에 있는 내부 인터페이스이다.
Map 자료구조를 보다 객체지향적인 설계를 하도록 유도하기 위한 것이다.Map.Entry 내부 인터페이스와 HashMap 안의 Map.Entry를 구현하고 있는 Node 내부 클래스를 확인할 수 있다.
Map.Entry
`boolean equals(Object o)`: 동일한 Entry 인지 비교
`Object getKey()`: Entry의 key 객체를 반환
`Object getValue()`: Entry의 value객체를 반환
`int hashCode()`: Entry의 해시코드 반환
`Object setValue(Object value)`: Entry의 value 객체를 지정된 객체로 바꾼다.
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
// Map.Entry 인터페이스를 구현하고 있는 Key-Value 쌍을 가지고 있는 HashMap의 Node 객체들의 Set 집합을 반환
Set<Map.Entry<String, Integer>> entry = map.entrySet();
System.out.println(entry); // [1=a, 2=b, 3=c]
// Set을 순회하면서 Map.Entry를 구현한 Node 객체에서 key와 value를 얻어 출력
for (Map.Entry<String, Integer> e : entry) {
System.out.printf("{ %s : %d }\n", e.getKey(), e.getValue());
/*
{ a : 1 }
{ b : 2 }
{ c : 3 }
*/
}
5.1 HashTable 클래스

자바 초기 버전에 나온 레거시 클래스
Key를 특정 해시 함수를 통해 해싱한 후 나온 결과를 배열의 인덱스로 사용하여 Value를 찾는 방식으로 동작
HashMap 보다 느리지만 동기화가 기본 지원
키와 값으로 null 허용 안됨.
5.2 HashMap 클래스
- Hashtable을 보완한 컬렉션
- 배열과 연결이 결합된 Hashing형태로, 키와 값을 묶어 하나의 데이터로 저장한다.
- 중복 허용하지 않고, 순서 보장하지 않음
- 키와 값으로 null 허용
- 추가, 삭제, 검색, 접근성이 모두 뛰어남
- HashMap 은 비동기로 작동하기 때문에 멀티 쓰레드 환경에서는 어울리지 않음(ConcurrentHashMap 사용)
5.3 LinkedHashMap 클래스
- HashMap을 상속하기 때문에 흡사하지만, Entr들이 연결 리스트를 구성하여 데이터의 순서 보장
- 일반적으로 Map 자료구조는 순서를 가지지 않지만, LinkedHashMap은 들어온 순서대로 순서를 가진다.
5.4 TreeMap 클래스

- 이진 검색 트리의 형태로 키와 값의 쌍으로 이루어진 데이터를 저장 (TreeSet과 같은 원리)
- TreeMap은 SortedMap 인터페이스를 구현하고 있어 Key 값을 기준으로 정렬되는 특징을 가지고 있다.
- 정렬된 순서로 키/값 쌍을 저장하므로 빠른 검색(특히 범위 검색)이 가능하다.
- 단, 키와 값을 저장하는 동시에 정렬을 해앟기에 저장시간이 다소 오래걸림
- 정렬되는 순서는 숫자 -> 알파벳 대문자 -> 알파벳 소문자 -> 한글 순이다.
5.5 Preperties 클래스
`Properties(String, String)` 의 형태로 저장하는 단순화된 key-value 컬렉션
주로 애플리케이션의 환경 설정과 관련된 속성 파일인 .properties 를 설정하는데 사용된다.
Properties AppProps = new Properties();
// Properties 컬렉션에 String : String 구조의 데이터 추가
AppProps.setProperty("Backcolor", "White");
AppProps.setProperty("Forecolor", "Blue");
AppProps.setProperty("FontSize", "12");
// test.properties 파일에 Properties 자료들을 저장
Path PropertyFile = Paths.get("test.properties");
try (Writer propWriter = Files.newBufferedWriter(PropertyFile)) {
AppProps.store(propWriter, "Property File Test");
} catch (IOException e) {
e.printStackTrace();
}

정리
ArrayList
리스트 자료구조 사용할 때 사용
순차적인 추가/삭제 제일 빠름
추가, 삭제 불리
LinkedList
- 요소 추가/삭제 유리
- 임의의 요소에 대한 접근성이 좋지 않음
HashMap / HashSet
- 임의의 요소에 대한 추가 / 삭제 / 검색 / 접근성 모두 뛰어남
- 검색에 최고 성능(get 메서드 시간복잡도: O(1))
TreeMap / TreeSet
- 요소 정렬이 필요할 때
- 검색(범위 검색)에 적합 -> HashMap 보단 떨어짐
LinkedHashMap / LinkedHashSet
- HashMap 과 HashSet에 저장 순서 유지 기능이 추가
Queue / Stack
- 스택, 큐 자료구조가 필요하면 ArrayDeque 사용
참고자료
- https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-Collections-Framework-%EC%A2%85%EB%A5%98-%EC%B4%9D%EC%A0%95%EB%A6%AC
- 공식문서
'언어 > JAVA' 카테고리의 다른 글
[JAVA] EOF 사용법 (0) | 2024.04.10 |
---|---|
Optional 올바르게 사용하자 (0) | 2024.03.30 |
Optional<T> 왜 사용하나 (0) | 2024.03.30 |
[JAVA] 예외 (0) | 2023.10.05 |
C언어에서 LinkedList라는 자료구조를 사용하려면 직접 구현해야함 → 자바는 JCF에서 만들어놓은 클래스를 사용하면 됨.
💡 직접 구현하는 것과 JCF 사용하는 것 중 무엇이 좋은가?
만들어 놓은데는 다 이유가 있다..
알고리즘의 속도와 안정성에 있어 자바 언어 개발진들이 수십년에 걸쳐 JVM에 최적화시켜 개량해왔으니 우리는 그걸 가져다 쓰면 된다.
장점
- 인터페이스와 다형성을 이용한 객체지향적 설계를 통해 표준화 되어 있기에, 사용법을 익히기에도 편리하고 재사용성이 높다
- 데이터 구조 및 알고리즘의 고성능 구현을 제공하여 프로그램의 성능과 품질을 향상
- 관련없는 API 산의 상호 운용성을 제공 (상위 인터페이스 타입을 업캐스팅하여 사용) → 인터페이스 중심으로 사용 → 객체지향적
- 이미 구현되어 있는 API를 제공하므로 새로운 API를 익히고 설계하는 시간이 줄어든다
- 소프트웨어 재사용을 촉진. 만일 자바에서 지원하지 않는 새로운 자료구조가 필요하다면, 컬렉션들을 재활용하여 조합하여 새로운 알고리즘을 만들어낼 수 있다.
Collcetion Framework에 저장할 수 있는 데이터는 오로지 객체 뿐.
primitive타입은 적재하지 못함. Wrapper 타입(기본 타입을 객체 타입으로 만들어주는 객체)으로 변환하도록 Boxing 과정을 거쳐야함.
Collection Framework의 종류

컬렉션 프레임워크는 크게 2가지로 나뉨
- Collection 인터페이스
- List와 Set 인터페이스를 구현한 컬렉션 클래스들은 공통부분이 많기 때문에, 공통된 부분을 모아둔 Collcetion 인터페이스에 상속되어 있다. → List, Set에서 사용하는 공통 메서드는 Collection인터페이스를 불러와 사용할 수 있다는 말
- Map 인터페이스
- Map 인터페이스: 컬렉션들은 두개의 데이터를 묶어 한쌍으로 다루기 때문에 Collcetion 인터페이스와 따로 분리되어 있다.
💡 Vector, Stack, Hashtable, Properites와 같은 클래스들은 컬렉션 프레임워크가 만들어지기 이전부터 존재하던 것이여서 컬렉션 프레임워크의 명명법을 따르지 않는다.
( … List, …Set, …Map) 이런 것들은 이전 java 버전과의 호환을 위해 남겨진 것으로 가급적 사용하지 않는 것이 좋다.
Iterable 인터페이스
컬렉션 인터페이스들의 가장 최상위 인터페이스
자료 순회할 때 이터레이터(Iterator) 객체를 다루는데, 이 이터레이터 객체를 관리하는 인터페이스이다.
default void forEach(Consumer<? super T> action)
: 함수형 프로그래밍 전용 루프 메서드Iterator<T> iterator()
: 컬렉션에서 이터레이터를 구현할 때 사용default Spliterator<T> splierator()
: 파이프라이닝 관련 메소드
💡Spliterator
Java 8 에 도입된 Spliterator 인터페이스는 시퀀스를 탐색하고 분할할 수 있다.
특히 병렬 Streams의 기본유틸리티이다.
-> 병렬 작업할 때 사용하는 메서드라고 생각하면 될 듯하다
💡Map 인터페이스에는 iterable 인터페이스를 상속받지 않음.
따라서 Map 컬렉션을 순회하려면 Stream을 사용하거나 간접적으로 키를 Collcetion으로 변환하여 루프문으로 순회하는 식으로 이용
Collcetion 인터페이스
List, Set, Queue에 상속을 하는 실질적인 최상위 컬렉션 타입
Collcetion을 구현한 객체를 업캐스팅하여 해당 자료구조에 자료를 삽입하거나 삭제, 탐색 기능을 할 수 있다.
개인적으로 많이 사용한 메서드들만 정리하겠다.
추가
boolean add(Object o) boolean addAll(Collection c)
컬렉션에 객체가 있는지 확인
boolean containse(Object o) boolean containsAll(Collcetion c)
삭제
boolean remove(Object o) boolean removeAll(Collection c)
컬렉션 비우기
void clear()
동일한 컬렉션인지 비교
boolean equals(Object o)
컬렉션이 비었는지 확인
boolean isEmpty()
컬렉션 사이즈 반환
int size()
컬렉션 -> 배열
Object[] toArray()
배열에 컬렉션 객체 저장
Object[] toArray(Object[] a)
JDK 1.8 부터 함수형 프로그래밍을 위해 parallelStream, removeIf, stream, forEach 디폴트(default)메서드가 추가됨
컬렉션 인터페이스 메서드에서 get()이 없는 이유
각 컬렉션 자료형마다 구현하는 자료구조가 제각각이기 때문에 최상위 타입으로 조회하기 까다롭기 때문
->
1. List 인터페이스

- 저장 순서가 유지되는 컬렉션을 구현하는데 사용
- 같은 요소의 중복 저장 허용
- index로 요소에 접근
- 요소 사이에 빈공간 허용하지 않음 -> 삽입/삭제 시 배열이동이 일어남
💡리스트와 배열의 차이
리스트: 자료형의 크기가 가변
배열: 자료형 크기가 불변
추가
void add(int idx, Object ele) boolean add(int idx, Collection c)
삭제
Object remove(int idx)
조회
Object get(int idx)
지정된 위치에 객체 저장
Object set(int idx, Object ele)
지정된 객체의 위치 반환
int indexOf(Object o) //순방향 int lastIndexOf(Object o) // 역방향
지정된 범위에 있는 객체 반환(슬라이스)
List subList(int fromIdx, int toIdx)
지정된 비교자(comparator)로 리스트 정렬
void sort(Comparator c)
1.1 ArrayList 클래스
- 배열을 이요하여 만든 리스트
- 데이터의 저장순서가 유지되고 중복을 허용
- 길이 가변
- 단방향 포인터 구조로 자료에 대한 순차적인 접근에 강점이 있어 조회가 빠르다
- 삭제 / 삽입이 느리다, 순차적으로 추가 / 삭제 하는 경우에 가장 빠르다.
1.2 Vector 클래스
ArrayList의 구형 버전(내부 구성이 거의 비슷)
ArrayList와의 차이는 모든 메서드가 동기화되어 있어 Thread-Safe하다는 점.
Vector는 구버전 자바와 호환성을 위해 남겨둔 것으로 잘 사용하지 않음.
만일 컬렉션에 동기화가 필요하다면Collcetions.synchronizedList()
메서드를 이용해 ArrayList를 동기화 처리하여 사용
1.3 Stack 클래스
- LIFO(후입선출)
- 들어올 때는 push, 나갈때는 pop
- Stack은 Vector를 상속하므로 문제점이 많아 잘 안쓰임. -> ArrayDeque 사용
2. Queue 인터페이스

- FIFO(선입선출)
삽입
boolean add(Object o) //저장공간 부족 시 illegalStaeException boolean offer(Obejct o)
삭제
Object remove() //비어있을 경우 NoSuchElementException Object poll()
조회
Object element() //비어있을 경우 NoSuchElementException Object peek() //비어있을 경우 null
2.1 PriorityQueue 클래스
- 우선순위 큐
- 우선순위 큐에 저장할 객체는 필수적으로 Comparable 인터페이스를 구현해야함.
compareTo()
메서드 로직에 따라 자료 객체의 우선순위를 결정하는 식으로 동작되기 때문 - 저장공간을 배열로 사용하고, 각 요소를 힙(heap) 형태로 저장
- null 저장 불가능
// 우선순위 큐에 저장할 객체는 필수적으로 Comparable를 구현 class Student implements Comparable<Student> { String name; // 학생 이름 int priority; // 우선순위 값 public Student(String name, int priority) { this.name = name; this.priority = priority; } @Override public int compareTo(Student user) { // Student의 priority 필드값을 비교하여 우선순위를 결정하여 정렬 if (this.priority < user.priority) { return -1; } else if (this.priority == user.priority) { return 0; } else { return 1; } } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", priority=" + priority + '}'; } }
public static void main(String[] args) { // 오름차순 우선순위 큐 Queue<Student> priorityQueue = new PriorityQueue<>(); priorityQueue.add(new Student("주몽", 5)); priorityQueue.add(new Student("세종", 9)); priorityQueue.add(new Student("홍길동", 1)); priorityQueue.add(new Student("임꺽정", 2)); // 우선순위 대로 정렬되어 있음 System.out.println(priorityQueue); // [Student{name='홍길동', priority=1}, Student{name='임꺽정', priority=2}, Student{name='주몽', priority=5}, Student{name='세종', priority=9}] // 우선순위가 가장 높은 값을 참조 System.out.println(priorityQueue.peek()); // Student{name='홍길동', priority=1} // 차례대로 꺼내기 System.out.println(priorityQueue.poll()); // Student{name='홍길동', priority=1} System.out.println(priorityQueue.poll()); // Student{name='임꺽정', priority=2} System.out.println(priorityQueue.poll()); // Student{name='주몽', priority=5} System.out.println(priorityQueue.poll()); // Student{name='세종', priority=9} }
3. Deque 인터페이스
- Deque(Double-Ended Queue)는 양쪽으로 넣고 빼는 것이 가능한 큐
- Deque -> Queue
- ArrayDeque, LinkedList -> Deque
3.1 ArrayDeque 클래스 -> 큐, Stack 대신 사용

- 스택으로 사용할 때 Stack 클래스보다 빠르며, 대기열로 사용할 때는 LinkedList 보다 빠르다.
- 사이즈에 제한이 없음
- null 저장 안됨
Deque | Queue | Stack |
offerLast() | offer() | push() |
pollLast() | pop() | |
pollFirst() | poll() | |
peekFirst() | peek() | |
peekLast() | peek() |
3.2 LinkedList 클래스
- LinkedList는 List 인터페이스와 Queue 인터페이스를 동시에 상속받고 있기 때문에, 스택/큐 로서도 응용이 가능하다.
- LinkedList 클래스에 큐 동작과 관련된 메서드를 지원한다.
- 노드(객체)를 연결하여 리스트처럼 만든 컬렉션(배열아님)
- 데이터의 중간 삽입, 삭제가 빈번할 경우 빠른 성능을 보장
- 임의의 요소에 대한 접근 성능은 좋지 않음
- 자바의 LinkedList는 Doubly LinkedList(양방향 포인터 구조)로 이루어져 있다.
- LinkedList는 리스트 용도 이외에도, 스택, 큐, 트리 등의 자료구조의 근간이 된다.
Queue<String> linkedList = new LinkedList<>(); // Queue 타입으로 받음 linkedList.offer("Hello"); linkedList.offer("World"); linkedList.offer("Power"); linkedList.poll(); // "Hello" - 선입선출 System.out.println(linkedList); // [World, Power]
💡 LinkedList 를 큐로 사용하는 이유
큐는 데이터를 꺼낼 때 항상 첫번째 저장된 데이터를 삭제하므로, ArrayList와 같은 배열 기반의 컬렉션 클래스를 사용한다면, 데이터를 꺼낼때마다 빈 공간이 생긴다.
List는 빈공간을 허용하지 않으므로 빈 공간을 채우기 위해 데이터의 이동 & 복사가 발생하므로 비효율적이다.
이런 이유로 데이터의 추가 / 삭제가 용이한 LinkedList로 큐를 구현하는 것이 적합
4. Set 인터페이스

- 데이터의 중복을 허용하지 않고 순서를 유지하지 않는 데이터 집합 리스트
- 순서 자체가 없으므로 인덱스로 객체를 검색해서 가져오는 get(index) 메서드가 존재하지 않음
- 중복 저장 불가능하고 Null값도 하나만 저장할 수 있다
삽입
boolean add(E e)
삭제
boolean remove(Object o)
boolean contains(Object o)
: 주어진 객체가 저장되어 있는지 리턴Iterator<E> iterator()
: 저장된 객체를 한번씩 가져오는 iterator를 리턴isEmpty()
: 컬렉션이 비어있는지 조사int size()
: 저장되어 있는 전체 객체수를 리턴void clear()
: 저장된 모든 객체를 삭제
4.1 HashSet 클래스

- 배열과 연결 노드를 결합한 자료구조 형태
- 가장 빠른 임의 검색 속도를 가진다
- 추가, 삭제, 검색, 접근성이 모두 뛰어남
- 대신 순서를 전혀 예측할 수 없다.
4.2 LinkedHashSet 클래스
- 순서를 가지는 Set 자료
- 추가된 순서 또는 가장 최근에 접근한 순서대로 접근 가능
- 만일 중복을 제거하는 동시에 순서를 유지하고 싶다면, HashSet 대신 LinkedHashSet을 사용
4.3 TreeSet 클래스
- 이진 검색 트리(binary search tree) 자료구조의 형태로 데이터를 저장
- 중복을 허용하지 않고, 순서를 가지지 않는다
- 대신 데이터를 정렬하여 저장하고 있다는 특징이다.
- 정렬, 검색, 범위 검색에 높은 성능을 뽐낸다

5. Map 인터페이스

- 키와 값의 쌍으로 연관지어 이루어진 데이터의 집합
- 값은 중복되서 저장될 수 있지만, 키는 해당 Map에서 고유해야함
- 만일 기존 저장된 데이터와 중복된 키와 값을 저장하면 기존의 값은 없어지고 마지막에 저장된 값이 남게 된다
- 저장 순서가 유지 되지 않는다.
조회
Object get(Object key)
삽입
void put(Object key, Object value) void putAll(Map t)
삭제
Object remove(Object key)
void clear()
: 모든 객체 삭제
boolean containsKey(Object key)
: 지정된 key 객체와 일치하는 객체가 있는지 확인
boolean containsValue(Object value)
: 지정된 value객체와 일치하는 객체가 있는지 확인
Set entrySet()
: Map에 저장된 key-value쌍을 Map.Entry 타입의 객체로 저장한 Set을 반환
boolean equals(Object o)
: 동일한 Map인지 비교
int size()
: 크기 반환
boolean isEmpty()
: Map이 비었는지 확인
Set keySet()
: Map에 저장된 모든 key객체를 반환
Collection values()
: Map에 저장된 모든 value객체를 반환
💡 Map에 저장되는 key-value 쌍의 노드 살펴보기
노드는 Map.Entry 인터페이스를 구현하고 있다.
Map.Entry 인터페이스는 Map 인터페이스 안에 있는 내부 인터페이스이다.
Map 자료구조를 보다 객체지향적인 설계를 하도록 유도하기 위한 것이다.Map.Entry 내부 인터페이스와 HashMap 안의 Map.Entry를 구현하고 있는 Node 내부 클래스를 확인할 수 있다.
Map.Entry
boolean equals(Object o)
: 동일한 Entry 인지 비교
Object getKey()
: Entry의 key 객체를 반환
Object getValue()
: Entry의 value객체를 반환
int hashCode()
: Entry의 해시코드 반환
Object setValue(Object value)
: Entry의 value 객체를 지정된 객체로 바꾼다.
Map<String, Integer> map = new HashMap<>(); map.put("a", 1); map.put("b", 2); map.put("c", 3); // Map.Entry 인터페이스를 구현하고 있는 Key-Value 쌍을 가지고 있는 HashMap의 Node 객체들의 Set 집합을 반환 Set<Map.Entry<String, Integer>> entry = map.entrySet(); System.out.println(entry); // [1=a, 2=b, 3=c] // Set을 순회하면서 Map.Entry를 구현한 Node 객체에서 key와 value를 얻어 출력 for (Map.Entry<String, Integer> e : entry) { System.out.printf("{ %s : %d }\n", e.getKey(), e.getValue()); /* { a : 1 } { b : 2 } { c : 3 } */ }
5.1 HashTable 클래스

자바 초기 버전에 나온 레거시 클래스
Key를 특정 해시 함수를 통해 해싱한 후 나온 결과를 배열의 인덱스로 사용하여 Value를 찾는 방식으로 동작
HashMap 보다 느리지만 동기화가 기본 지원
키와 값으로 null 허용 안됨.
5.2 HashMap 클래스
- Hashtable을 보완한 컬렉션
- 배열과 연결이 결합된 Hashing형태로, 키와 값을 묶어 하나의 데이터로 저장한다.
- 중복 허용하지 않고, 순서 보장하지 않음
- 키와 값으로 null 허용
- 추가, 삭제, 검색, 접근성이 모두 뛰어남
- HashMap 은 비동기로 작동하기 때문에 멀티 쓰레드 환경에서는 어울리지 않음(ConcurrentHashMap 사용)
5.3 LinkedHashMap 클래스
- HashMap을 상속하기 때문에 흡사하지만, Entr들이 연결 리스트를 구성하여 데이터의 순서 보장
- 일반적으로 Map 자료구조는 순서를 가지지 않지만, LinkedHashMap은 들어온 순서대로 순서를 가진다.
5.4 TreeMap 클래스

- 이진 검색 트리의 형태로 키와 값의 쌍으로 이루어진 데이터를 저장 (TreeSet과 같은 원리)
- TreeMap은 SortedMap 인터페이스를 구현하고 있어 Key 값을 기준으로 정렬되는 특징을 가지고 있다.
- 정렬된 순서로 키/값 쌍을 저장하므로 빠른 검색(특히 범위 검색)이 가능하다.
- 단, 키와 값을 저장하는 동시에 정렬을 해앟기에 저장시간이 다소 오래걸림
- 정렬되는 순서는 숫자 -> 알파벳 대문자 -> 알파벳 소문자 -> 한글 순이다.
5.5 Preperties 클래스
Properties(String, String)
의 형태로 저장하는 단순화된 key-value 컬렉션
주로 애플리케이션의 환경 설정과 관련된 속성 파일인 .properties 를 설정하는데 사용된다.
Properties AppProps = new Properties(); // Properties 컬렉션에 String : String 구조의 데이터 추가 AppProps.setProperty("Backcolor", "White"); AppProps.setProperty("Forecolor", "Blue"); AppProps.setProperty("FontSize", "12"); // test.properties 파일에 Properties 자료들을 저장 Path PropertyFile = Paths.get("test.properties"); try (Writer propWriter = Files.newBufferedWriter(PropertyFile)) { AppProps.store(propWriter, "Property File Test"); } catch (IOException e) { e.printStackTrace(); }

정리
ArrayList
리스트 자료구조 사용할 때 사용
순차적인 추가/삭제 제일 빠름
추가, 삭제 불리
LinkedList
- 요소 추가/삭제 유리
- 임의의 요소에 대한 접근성이 좋지 않음
HashMap / HashSet
- 임의의 요소에 대한 추가 / 삭제 / 검색 / 접근성 모두 뛰어남
- 검색에 최고 성능(get 메서드 시간복잡도: O(1))
TreeMap / TreeSet
- 요소 정렬이 필요할 때
- 검색(범위 검색)에 적합 -> HashMap 보단 떨어짐
LinkedHashMap / LinkedHashSet
- HashMap 과 HashSet에 저장 순서 유지 기능이 추가
Queue / Stack
- 스택, 큐 자료구조가 필요하면 ArrayDeque 사용
참고자료
- https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-Collections-Framework-%EC%A2%85%EB%A5%98-%EC%B4%9D%EC%A0%95%EB%A6%AC
- 공식문서
'언어 > JAVA' 카테고리의 다른 글
[JAVA] EOF 사용법 (0) | 2024.04.10 |
---|---|
Optional 올바르게 사용하자 (0) | 2024.03.30 |
Optional<T> 왜 사용하나 (0) | 2024.03.30 |
[JAVA] 예외 (0) | 2023.10.05 |