Problem Source: GitHub - Sw_Pilot_Java (Chapter 2 / Step 2 - 3)
스택(Stack)은 '쌓다', '더미'라는 뜻을 가지고 있습니다. 식당에 쌓여 있는 접시 더미나, 총기의 탄창을 떠올리면 이해하기 쉽습니다.
가장 마지막에 들어간 데이터가 가장 먼저 나오는 LIFO(Last In First Out, 후입선출) 구조를 가지고 있으며, 이는 먼저 들어간 데이터가 먼저 나오는 Queue(FIFO)와 정반대되는 개념입니다.

1. 스택(Stack)의 구조와 특징
- LIFO 구조: 나중에 넣은(Push) 데이터가 먼저 나옵니다(Pop).
- 활용 예시: 웹 브라우저 뒤로 가기, 편집기 실행 취소(Undo/Redo), 수식의 괄호 검사, JVM의 Stack 메모리 영역 등.
- Java 특징:
java.util.Stack클래스는Vector클래스를 상속받아 구현되었으므로 Thread-Safe하다는 특징이 있습니다.
2. Stack 클래스 주요 메서드
자바에서 스택을 다룰 때 주로 사용하는 메서드들입니다.
| 메서드 | 설명 | 반환값 |
|---|---|---|
| push(item) | 스택의 맨 위에 객체를 저장합니다. | 저장된 객체 |
| pop() | 맨 위의 객체를 꺼내서 반환합니다. (제거됨) | 꺼낸 객체 |
| peek() | 맨 위의 객체를 확인만 합니다. (제거 안 됨) | 맨 위 객체 |
| empty() | 스택이 비어있는지 확인합니다. | boolean |
| search(o) | 객체의 위치를 반환합니다. (1부터 시작) | 인덱스 (없으면 -1) |
3. 실전 사용 예제
기본적인 Push와 Pop
데이터를 넣고(push) 꺼내는(pop) 가장 기초적인 동작입니다. 꺼내면 데이터는 스택에서 사라집니다.
Stack<Integer> stack = new Stack<>();
// 1. 요소 추가 (Push)
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack); // [1, 2, 3]
// 2. 요소 꺼내기 (Pop - LIFO)
System.out.println(stack.pop()); // 3 (가장 마지막에 넣은 것)
System.out.println(stack.pop()); // 2
System.out.println(stack); // [1] (꺼낸 값은 사라짐)
최상단 값 확인하기 (Peek)
peek()은 데이터를 꺼내지 않고 "다음에 나올 값이 뭔지 확인만" 하고 싶을 때 사용합니다. 데이터가 제거되지 않습니다.
Stack<String> stack = new Stack<>();
stack.push("Apple");
stack.push("Banana");
stack.push("Cherry");
// 맨 위 값 확인 (제거 X)
System.out.println("Top Element: " + stack.peek()); // Cherry
System.out.println("Stack Size: " + stack.size()); // 3 (사이즈 유지됨)
// 값을 꺼냄 (제거 O)
System.out.println("Pop Element: " + stack.pop()); // Cherry
System.out.println("Stack Size: " + stack.size()); // 2
위치 검색 (search) 주의사항
search() 메서드는 배열의 인덱스(0부터 시작)와 다르게, 맨 위에서부터 몇 번째에 있는지(1부터 시작)를 반환합니다.
Stack<String> stack = new Stack<>();
stack.push("HI");
stack.push("HELLO");
stack.push("EARTH");
// "EARTH"는 맨 위에 있으므로 1 반환
System.out.println(stack.search("EARTH")); // 1
// "HI"는 세 번째로 꺼내지므로 3 반환
System.out.println(stack.search("HI")); // 3
4. Stack 클래스는 Deprecated 되었습니다!
결론부터 말하자면, 실무에서 java.util.Stack 클래스는 사용을 지양해야 합니다.

Stack은
Vector를 상속받았습니다. Vector는 중간에 데이터를 삽입할 수 있는 add(index, val) 메서드를 가지고 있는데, 이를 Stack도 그대로 물려받았습니다."맨 위에서만 넣고 빼야 한다"는 스택의 원칙이 깨질 위험이 있습니다.
Stack<String> stack = new Stack<>();
stack.push("One");
stack.push("Two");
// 스택의 원칙 위배! (중간에 강제 삽입 가능)
stack.add(0, "Bug");
// pop() 결과가 예상과 달라질 수 있음
System.out.println(stack.pop()); // "Two" (Bug가 아님)
또한, Vector의 모든 메서드가 synchronized 처리되어 있어, 싱글 스레드 환경에서도 불필요한 성능 저하가 발생합니다.
5. 권장되는 해결책: Deque (ArrayDeque)
Java 공식 문서에서도 Stack 대신 Deque(덱) 인터페이스의 구현체인 ArrayDeque를 사용할 것을 권장합니다.

Deque는 양쪽 끝에서 데이터를 넣고 뺄 수 있어, 스택(LIFO)과 큐(FIFO)의 기능을 모두 완벽하게 수행할 수 있습니다.

Stack 처럼 사용하기 (LIFO)
push()와 pop() 메서드를 사용하면 스택과 동일하게 동작합니다.
/* Stack 처럼 사용하기 */
Deque<String> stack = new ArrayDeque<>();
// 담기 (Push)
stack.push("a");
stack.push("b");
stack.push("c");
stack.push("d");
stack.push("e");
System.out.println(stack); // [e, d, c, b, a] (Last In First Out)
// 꺼내기 (Pop)
System.out.println(stack.pop()); // e
System.out.println(stack.pop()); // d
System.out.println(stack); // [c, b, a]
Queue 처럼 사용하기 (FIFO)
offer()와 poll() 메서드를 사용하면 큐와 동일하게 동작합니다.
/* Queue 처럼 사용하기 */
Deque<String> queue = new ArrayDeque<>();
// 담기 (Offer)
queue.offer("a");
queue.offer("b");
queue.offer("c");
queue.offer("d");
queue.offer("e");
System.out.println(queue); // [a, b, c, d, e] (First In First Out)
// 꺼내기 (Poll)
System.out.println(queue.poll()); // a
System.out.println(queue.poll()); // b
System.out.println(queue); // [c, d, e]
2. 기존
java.util.Stack은 낡은 Vector를 상속받아 설계 결함이 있다.3. 따라서 스택이 필요할 때는
Deque<T> stack = new ArrayDeque<>();를 쓰자!References & Sources
'Language > Java' 카테고리의 다른 글
| [JAVA] 인터페이스 vs 추상클래스 차이점 정리 (0) | 2026.01.07 |
|---|---|
| [JAVA] Collection Framework & Collections Class _ Part 1 (0) | 2025.12.16 |
| [JAVA] Getter/Setter 이중성 & 문제점 Refactoring (1) | 2025.12.12 |
| [JAVA] 접근제한자 & 캡슐화 (0) | 2025.12.12 |
| [JAVA] 객체 지향 프로그래밍 4대 원칙 (0) | 2025.12.12 |
