[JAVA] Stack 구현 & Stack Class의 문제점 (feat. Deque)

2025. 12. 19. 18:33·Language/Java
📚
Java Collection: Stack & Deque
Problem Source: GitHub - Sw_Pilot_Java (Chapter 2 / Step 2 - 3)
LIFO 구조인 스택의 개념과 사용법, 그리고 현대적인 대체제인 Deque를 알아봅니다.

스택(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 클래스를 상속하도록 설계 되어 있음
⚠️ 이유 1: Vector 상속의 문제점
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를 사용할 것을 권장합니다.

JAVA 공식 문서

 

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]

 

1. Stack은 LIFO(후입선출) 구조이다.
2. 기존 java.util.Stack은 낡은 Vector를 상속받아 설계 결함이 있다.
3. 따라서 스택이 필요할 때는 Deque<T> stack = new ArrayDeque<>();를 쓰자!

         References & Sources

  • Inpa Dev 👨‍💻:티스토리 - 자바 Stack 구조 및 사용법 정리
  • Programiz - Stack Data Structure

'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
'Language/Java' 카테고리의 다른 글
  • [JAVA] 인터페이스 vs 추상클래스 차이점 정리
  • [JAVA] Collection Framework & Collections Class _ Part 1
  • [JAVA] Getter/Setter 이중성 & 문제점 Refactoring
  • [JAVA] 접근제한자 & 캡슐화
hlxecz
hlxecz
1인분 개발자가 되고 싶은 개발 기록
  • hlxecz
    H.Dev Log
    hlxecz
  • 전체
    오늘
    어제
    • 분류 전체보기 (12)
      • Language (7)
        • Java (7)
        • C (0)
        • PHP (0)
        • Python (0)
      • Framewrok (0)
        • Spring (0)
      • Data (0)
        • DBMS (0)
      • Cloud (0)
        • Amazon Cloud (0)
      • Knowledge (3)
        • 자료구조 (0)
        • 알고리즘 (1)
        • 디자인 패턴 (2)
      • DevOps (0)
      • Dev Kit (0)
        • InteliJ (0)
        • VSCode (0)
      • TEST (2)
        • Testing (2)
        • Error (0)
      • ETC (0)
        • 일상 (0)
  • 블로그 메뉴

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

  • 공지사항

  • 인기 글

  • 태그

    string
    빅오표기법
    재귀함수
    문제풀이
    OOP
    collections
    바밀로니아
    Interface
    자바
    BIG-O
    Stack
    Solid
    캡슐화
    Collection
    피드백
    시간복잡도
    인터페이스 vs 추상클래스
    문제점
    디자인 패턴
    setter
    getter
    GOF
    생각정리
    알고리즘
    인터페이스
    Java
    Abstract
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
hlxecz
[JAVA] Stack 구현 & Stack Class의 문제점 (feat. Deque)
GitHub 상단으로

티스토리툴바