목표
- Queue의 특징을 익힌다.
- Queue 인터페이스를 구현하는 클래스(ArrayBlockingQueue)의 사용법과 특징을 익힌다.
개요
Queue란 FIFO(First In First Out)의 특징을 갖는 자료 구조이다. 즉, 먼저 들어온 값이 먼저 나가는 자료구조이다.
Kotlin에서는 Queue를 구현하기 위해 JCF(Java Collection Framework)에서 제공하는 Queue Interface를 이용한다.
하지만, Queue는 단순한 인터페이스이므로, 인터페이스를 구현하는 Class를 사용해야 하는데, 우리는 우리는 그중 ArrayBlockingQueue를 사용하여 Queue를 다루어본다.
생성
Queue 인터페이스를 이용하기 위해서는 인터페이스를 구현하는 구현체를 이용해야 한다. 그 중 대표적인 것이 LinkedList와 ArrayBlockingQueue이다. 우리는 이 글에서 ArrayBlockingQueue를 이용한 Queue을 생성을 다룬다.
ArrayBlockingQueue를 이용한 Queue를 생성하기 위해서는 타입에 Queue를 넣고 구현부에 ArrayBlockingQueue의 생성자를 넣어야 한다. ArrayBlockingQueue 이용하여 생성된 Queue는 Capacity가 지정되어 있으며, Capacity로 지정된 값만큼 Array로 잡혀 크기 수정이 불가능하다.
val queueArray: Queue<Int> = ArrayBlockingQueue<Int>(3)
이 Queue의 특징은 내부에 Lock을 잡는 로직을 가지고 있어, Thread Safe한 연산을 지원한다는 점이다. 하지만 우리의 이 글에서의 관심사는 크기가 지정된 Queue에 대한 것이므로 넘어간다.
조작
Queue Interface에는 다음의 6가지 연산을 지원한다.
- add(element : E) : Boolean
- offer(element : E) : Boolean
- remove() : E
- poll() : E
- element() : E
- peek() : E
입력[add, offer], 제거[remove, poll], 확인[element, peek]은 같은 연산을 수행하지만, 각각 세부 동작이 다르다. 지금부터 함께 살펴보자
add, offer
add와 offer은 값을 Queue에 추가해주기 위한 연산이다.
add는 Queue의 Capacity 인한 오류 발생 시 Exception이 발생하고, offer는 발생하지 않는다는게 차이점이다. 만약 Capacity가 모두 찼다면 add는 IllegaStateException을 발생시키고, offer은 발생시키지 않는다.
ArrayBlockingQueue에서는 용량 값에 제한을 줄 수 있어 주의해서 연산 값을 주의해서 써야 한다.
val queueArray: Queue<Int> = ArrayBlockingQueue<Int>(3) // 용량을 3으로 설정
queueArray.add(1) // [1]
queueArray.add(2) // [1, 2]
queueArray.add(3) // [1, 2, 3]
queueArray.offer(4) // [1, 2, 3] No error thrown
queueArray.add(4) // Exception in thread "main" java.lang.IllegalStateException: Queue full
remove, poll
remove와 poll은 Queue에서 값을 빼내기 위한 연산이다. remove와 poll 수행 시 가장 먼저 들어간 데이터가 return 된다.
remove와 poll 또한 값이 null이 나올 경우 exception이 발생하는지 하지 않는지에 대한 차이점을 가지고 있다. remove는 더이상 빼낼 데이터가 없을 경우 NoSuchElementException을 발생시키고, poll은 null을 리턴한다.
val queueArray: Queue<Int> = ArrayBlockingQueue<Int>(3)
queueArray.add(1)
queueArray.remove()
queueArray.remove() // Exception in thread "main" java.util.NoSuchElementException
val queueArray: Queue<Int> = ArrayBlockingQueue<Int>(3)
queueArray.add(1)
queueArray.poll()
queueArray.poll() // null , No Error Thrown
element, peek
element와 peek은 현재 Queue의 Head에 어떤 값이 들어있는지 확인하기 위한 연산이다. Queue를 변화시키지 않으면서 맨 앞에 있는 element의 값을 보기 위한 것이다.
element와 peek의 차이점은 마찬가지로 error에 대한 handling이 되어있는지 되어있지 않은지이다. element는 값이 없으면 NoSuchElementException을 발생시키지만, peek은 null을 return 한다.
val queueArray: Queue<Int> = ArrayBlockingQueue<Int>(3)
queueArray.add(1)
queueArray.poll()
queueArray.peek() // null, No error thrown
queueArray.element() // Exception in thread "main" java.util.NoSuchElementException