Map, Stack, Queue
1. 컬렉션 프레임워크 - Map 소개
Map은
- 키-값 쌍을 저장하는 자료 구조
- 순서 보장 X, 키는 중복 X, 값은 중복 O
- 키를 통해 값을 빠르게 검색 가능
- 자바는 HashMap, TreeMap, LinkedHashMap 등 다양한 Map 구현체를 제공한다.
이 중 HashMap을 가장 많이 사용한다.

Map 인터페이스의 주요 메서드
| 메서드 | 설명 |
| put(K key, V value) | 키와 값을 저장. 같은 키가 있으면 값을 덮어씀. |
| putIfAbsent(K key, V value) | 키가 없을 때만 값을 저장. 기존 값이 있으면 무시. |
| get(Object key) | 해당 키에 연결된 값을 반환. |
| getOrDefault(Object key, V defaultValue) | 키가 없으면 기본값을 반환. |
| remove(Object key) | 해당 키와 값을 제거. |
| containsKey(Object key) | 키 존재 여부 확인. |
| containsValue(Object value) | 값 존재 여부 확인. |
| keySet() | 모든 키를 Set으로 반환. 반복 처리에 유용. |
| entrySet() | 키-값 쌍을 Set<Map.Entry<K,V>>로 반환. 전체 순회에 자주 사용. |
| isEmpty() | 맵이 비어 있는지 확인. |
Entry
Entry는 키-값의 쌍으로 이루어진 간단한 객체이다.

키 목록 조회 Set<String> keySet = studentMap.keySet()
Map의 key는 중복 허용 X
∴ Map의 모든 key 목록을 조회하는 keySet()을 호출 -> 중복을 허용하지 않는 자료 구조인 Set을 반환
값 목록 조회 Collection<Integer> values = studentMap.values()
Map의 값 목록은 중복 O, 순서 보장 X 이므로 Set과 List로 반환 X
∴ Collection으로 반환한다.
putIfAbsent()
Map의 같은 키에 다른 값을 저장하면, 기존 값을 교체한다.
putIfAbsent() -> 키에 값이 없는 경우에만 데이터가 저장된다.
2. 컬렉션 프레임워크 - Map 구현체
Map은 인터페이스이므로 직접 인스터스 생성은 불가하고, Map 인터페이스를 구현한 여러 클래스를 통해 사용할 수 있다.
ex) HashMap, TreeMap, LinkedHashMap
Set vs Map
- Set 과 Map 은 거의 같다. 단지 옆에 Value의 유무 차이일 뿐이다.
- 실제로 자바 HashSet 의 구현은 대부분 HashMap 의 구현을 가져다 사용한다.
- Map 에서 Value 만 비워두면 Set 으로 사용할 수 있다.
- HashMap, LinkedHashMap, TreeMap의 특징은 각각 Set에서 학습한 내용과 거의 같다.
- Set과 비교해서 Map은
- Key를 사용하여 해시 코드를 생성한다.
- Entry를 사용해서 Key, Value를 묶어서 저장한다.
- 주의! Map의 Key로 사용되는 객체는 hashCode(), equals()를 반드시 구현해야 한다.
- 실무에서는 Map이 필요한 경우, HashMap을 많이 사용한다.
그리고 순서 유지, 정렬의 필요에 따라서 LinkedHashMap, TreeMap을 선택한다.

- 이렇게 해시를사용해서 키와 값을 저장하는 자료 구조를 일반적으로 해시 테이블이라 한다.
- HashSet 은 해시 테이블의 주요 원리를 사용하지만,
키-값 저장 방식 대신 키만 저장하는 특수한 형태의해시 테이블이라고 생각하면 된다.
코드로 확인해보는 HashMap, LinkedHashMap, TreeMap 의 특징
import java.util.*;
public class JavaMapMain {
public static void main(String[] args) {
run(new HashMap<>());
run(new LinkedHashMap<>());
run(new TreeMap<>());
}
private static void run(Map<String, Integer> map) {
System.out.println("map = " + map.getClass());
map.put("C", 10);
map.put("B", 20);
map.put("A", 30);
map.put("1", 40);
map.put("2", 50);
Set<String> keySet = map.keySet();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
System.out.print(key + "=" + map.get(key) + " ");
}
System.out.println();
}
}
실행 결과
map = class java.util.HashMap
A=30 1=40 B=20 2=50 C=10
map = class java.util.LinkedHashMap
C=10 B=20 A=30 1=40 2=50
map = class java.util.TreeMap
1=40 2=50 A=30 B=20 C=10
- HashMap : 순서 보장 X
- LinkedHashMap : 키를 기준으로 입력한 순서 보장 O
- TreeMap : 키 값을 기준으로 정렬
3. 스택 자료 구조
스택 구조 (후입 선출, LIFO, Last In First Out)


- 1(넣기) -> 2(넣기) -> 3(넣기) -> 3(빼기) -> 2(빼기) -> 1(빼기) (나중에 입력한 값이 먼저 나온다.)
- push 스택에 값을 넣는 것, pop 스택에서 값을 꺼내는 것
import java.util.Stack;
//Stack은 사용하면 안됨 -> Deque를 대신 사용
public class StackMain {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack);
// 다음 꺼낼 요소 확인(꺼내지 않고 단순 조회만)
System.out.println("stack.peek() = " + stack.peek());
// 스택 요소 뽑기
System.out.println("stack.pop() = " + stack.pop());
System.out.println("stack.pop() = " + stack.pop());
System.out.println("stack.pop() = " + stack.pop());
System.out.println(stack);
}
}
실행 결과
[1, 2, 3]
stack.peek() = 3
stack.pop() = 3
stack.pop() = 2
stack.pop() = 1
[]
주의! Stack 클래스는 사용 X -> Deque를 사용하는 것이 좋다.
4. 큐 자료 구조
큐 구조(선입 선출, FIFO, First In First Out)

- 1(넣기) -> 2(넣기) -> 3(넣기) -> 1(빼기) -> 2(빼기) -> 3(빼기) (먼저 입력한 값이 먼저 나온다.)
- offer 큐에 값을 넣는 것, poll 큐에서 값을 꺼내는 것
컬렉션 프레임워크 Queue

- Queue 인터페이스는 List, Set 과 같이 Collection 의 자식이다.
- Queue 의 대표적인 구현체는 ArrayDeque, LinkedList 가 있다.
- LinkedList 는 Deque 와 List 인터페이스를 모두 구현한다.
import java.util.ArrayDeque;
import java.util.LinkedList;
import java.util.Queue;
public class QueueMain {
public static void main(String[] args) {
Queue<Integer> queue = new ArrayDeque<>();
//Queue<Integer> queue = new LinkedList<>();
//데이터 추가
queue.offer(1);
queue.offer(2);
queue.offer(3);
System.out.println(queue);
//다음 꺼낼 데이터 확인(꺼내지 않고 단순 조회만)
System.out.println("queue.peek() = " + queue.peek());
//데이터 꺼내기
System.out.println("poll = " + queue.poll());
System.out.println("poll = " + queue.poll());
System.out.println("poll = " + queue.poll());
System.out.println(queue);
}
}
실행 결과
[1, 2, 3]
queue.peek() = 1
poll = 1
poll = 2
poll = 3
[]
5. Deque 자료 구조
Deque
- 양쪽 끝에서 요소를 추가하거나 제거할 수 있다.
- Deque는 일반적인 큐(Queue)와 스택(Stack)의 기능을 모두 포함하고 있다.

- offerFirst() : 앞에 추가한다.
- offerLast() : 뒤에 추가한다.
- pollFirst() : 앞에서 꺼낸다.
- pollLast() : 뒤에서 꺼낸다.
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeMain {
public static void main(String[] args) {
Deque<Integer> deque = new ArrayDeque<>();
//Deque<Integer> deque = new LinkedList<>();
// 데이터 추가
deque.offerFirst(1);
System.out.println(deque);
deque.offerFirst(2);
System.out.println(deque);
deque.offerLast(3);
System.out.println(deque);
deque.offerLast(4);
System.out.println(deque);
// 다음 꺼낼 데이터 확인(꺼내지 않고 단순 조회만)
System.out.println("deque.peekFirst() = " + deque.peekFirst());
System.out.println("deque.peekLast() = " + deque.peekLast());
// 데이터 꺼내기
System.out.println("pollFirst = " + deque.pollFirst());
System.out.println("pollFirst = " + deque.pollFirst());
System.out.println("pollLast = " + deque.pollLast());
System.out.println("pollLast = " + deque.pollLast());
System.out.println(deque);
}
}
실행 결과
[1]
[2, 1]
[2, 1, 3]
[2, 1, 3, 4]
deque.peekFirst() = 2
deque.peekLast() = 4
pollFirst = 2
pollFirst = 1
pollLast = 4
pollLast = 3
[]
Deque 구현체와 성능 테스트
Deque의 대표적인 구현체는 ArrayDeque, LinkedList 가 있다. 이 둘 중에 ArrayDeque 가 모든 면에서 더 빠르다.
6. Deque와 Stack, Queue
Deque 는 양쪽으로 데이터를 입력하고 출력할 수 있으므로, 스택과 큐의 역할을 모두 수행할 수 있다.
Deque 를 Stack 과 Queue 로 사용하기 위한 메서드 이름까지 제공한다.
Deque - Stack
Stack 자료 구조가 필요하면, Deque에 ArrayDeque 구현체를 사용한다.
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeStackMain {
public static void main(String[] args) {
Deque<Integer> deque = new ArrayDeque<>();
//Deque<Integer> deque = new LinkedList<>();
// 데이터 추가
deque.push(1);
deque.push(2);
deque.push(3);
System.out.println(deque);
// 다음 꺼낼 데이터 확인(꺼내지 않고 단순 조회만)
System.out.println("deque.peek() = " + deque.peek());
// 데이터 꺼내기
System.out.println("pop = " + deque.pop());
System.out.println("pop = " + deque.pop());
System.out.println("pop = " + deque.pop());
System.out.println(deque);
}
}
실행 결과
[3, 2, 1]
deque.peek() = 3
pop = 3
pop = 2
pop = 1
[]
Deque - Queue
Deque 인터페이스는 Queue 인터페이스의 자식이기 때문에,
단순히 Queue 의 기능만 필요하면 Queue 인터페이스를 사용하고, 더 많은 기능이 필요하다면 Deque 인터페이스를 사용하면 된다.
구현체로는 성능이 빠른 ArrayDeque를 사용한다.
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeQueueMain {
public static void main(String[] args) {
Deque<Integer> deque = new ArrayDeque<>();
//Deque<Integer> deque = new LinkedList<>();
//데이터 추가
deque.offer(1);
deque.offer(2);
deque.offer(3);
System.out.println(deque);
//다음 꺼낼 데이터 확인(꺼내지 않고 단순 조회만)
System.out.println("deque.peek() = " + deque.peek());
//데이터 꺼내기
System.out.println("poll = " + deque.poll());
System.out.println("poll = " + deque.poll());
System.out.println("poll = " + deque.poll());
System.out.println(deque);
}
}
실행 결과
[1, 2, 3]
deque.peek() = 1
poll = 1
poll = 2
poll = 3
[]