У багатьох людей слово «черга» викликає дуже мало приємних асоціацій. Але сьогодні ми говоримо про інші черги — в Java. Чергою в Java вважається все, що успадковує інтерфейс Queue, який зі свого боку розширює Collection. Це означає, що з чергами можна працювати, як із колекціями.

Черги в Java працюють за двома принципами: FIFO і LIFO.

FIFO — First In First Out, принцип звичайної черги (звичайно, якщо немає тих, кому потрібно «тільки запитати»), у якому перший елемент потрапляє у чергу і першим виходить із неї.

LIFO — Last In First Out, принцип стека, у якому останній елемент, доданий до черги, першим вийде із неї. Наприклад, як з колодою карт: ти братимеш всі карти зверху по одній, щоб дійти до кінця.

Ієрархія Queue в Java виглядає так:

Тут видно, що у Queue має 3 класи реалізації: LinkedList, ArrayDeque і PriorityQueue. LinkedList і ArrayDeque успадковує безпосередньо не від Queue, а від Deque.

Deque — це інтерфейс, який додали у 6 версії Java. Він містить низку корисних для черг методів і дає можливість черзі функціонувати як двобічна черга. Тобто працювати за принципом FIFO FIFO або LIFO.

Одним із двох спадкоємців Deque є ArrayDeque. Він підтримує двобічну структуру даних черги, що дає можливість вставляти та видаляти елементи з обох боків. Також він – динамічний масив, який може автоматично збільшувати свій розмір.

Є ще клас PriorityQueue, прямий спадкоємець Queue: принцип його роботи відрізняється від спадкоємців Dequeue.

PriorityQueue — це черга з пріоритетом, яка за замовчуванням розміщує елементи згідно з природним порядком сортування. Для сортування тут використовується Comparable та Comparator. Принцип тут такий самий, як і з TreeSet або TreeMap — класів, які дотримуються інтерфейсу Comparable і мають свій порядок сортування.

PriorityQueue<String> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(String::length));

priorityQueue.add("Andrew");
priorityQueue.add("John");
priorityQueue.add("Rob");

while (!priorityQueue.isEmpty()) {
   System.out.println(priorityQueue.remove());
}

Запустивши цей приклад у консолі, ти отримаєш:

Rob
John
Andrew

Оскільки ми працюємо з чергами, а не зі звичайними колекціями, ми повинні видалити елемент зі списку. Використовуємо цю конструкцію:

while (!priorityQueue.isEmpty()) {
            System.out.println(priorityQueue.remove());
}

Інтерфейс Deque успадковує методи Queue і додає низку своїх цікавих методів:

void addFirst(Е obj) Додає елемент obj на початок черги
void addLast(Е obj) Додає елемент obj у кінець черги
Е getFirst() Повертає перший елемент із черги
Е getLast() Повертає останній елемент із черги
boolean offerFirst(Е obj) Додає елемент obj на початок черги та повертає true, якщо елемент доданий, інакше поверне false
boolean offerLast(E obj) Додає елемент obj в кінець черги та повертає true, якщо елемент доданий, інакше поверне false
Е рор() Витягує перший елемент із черги та видаляє його
void push(Е obj) Додає елемент obj на початок черги
Е peekFirst() Повертає (але не видаляє) перший елемент із черги
Е peekLast() Повертає (але не видаляє) останній елемент із черги
Е pollFirst() Повертає та видаляє перший елемент із черги, поверне null, якщо немає елементів
Е pollLast() Повертає та видаляє останній елемент із черги, поверне null, якщо немає елементів
Е removeLast() Повертає та видаляє перший елемент черги, створить виняток, якщо немає елементів
Е removeFirst() Повертає та видаляє останній елемент черги, створить виняток, якщо немає елементів
boolean removeFirstOccurrence(Object obj) Видаляє перше входження obj з черги
boolean removeLastOccurrence(Object obj) Видаляє останнє входження obj з черги

Давай тепер розглянемо кілька із них на практиці.

Додамо спочатку елемент у чергу:

Deque<String> deque = new ArrayDeque<>();

        deque.add("Apple"); // Додає елемент Apple у кінець черги
        deque.addFirst("Orange"); // Додає елемент Orange на початок черги
        deque.addLast("Pineapple"); // Додає елемент Pineapple у кінець черги

        System.out.println(deque);
[Orange, Apple, Pineapple]

Тепер отримаємо значення з черги:

Deque<String> deque = new ArrayDeque<>();

deque.add("Apple");
        deque.addFirst("Orange");
        deque.addLast("Pineapple");


        System.out.println("The First element is: "+ deque.getFirst());

        System.out.println("The Last element is: " + deque.getLast());

    }

Цей код виведе в консолі перший та останній елемент черги.

The First element is: Orange
The Last element is: Pineapple

Deque<String> deque = new ArrayDeque<>();

        deque.add("Apple");
        deque.addFirst("Orange");
        deque.addLast("Pineapple");
        deque.add("Lemon");

System.out.println(deque.pop()); // витягне та видалить верхній елемент черги
System.out.println(deque.poll()); // витягне та видалить верхній елемент черги

System.out.println(deque);

Запустивши цей код, отримаємо:

Orange
Apple

[Pineapple, Lemon]

Різниця між методами pop() і poll() у тому, що pop() викликає виняток NoSuchElementException за порожнього списку, а poll() поверне null.

Тепер розглянемо методи pollFirst() і pollLast().

Deque<String> deque = new ArrayDeque<>();

        deque.add("Apple");
        deque.addFirst("Orange");
        deque.addLast("Pineapple");
        deque.add("Lemon");

System.out.println(deque.pollFirst()); // витягне та видалить перший елемент черги
System.out.println(deque.pollLast()); // витягне та видалить останній елемент черги.
System.out.println(deque);
Orange
Lemon
[Apple, PineApple]

Обидва методи повертають і видаляють значення з черги.

Приклад використання методів peekFirst() i peekLast():

Deque<String> friends = new ArrayDeque<>();

friends.add("John");
friends.add("Rob");
friends.add("Greg");
friends.add("Max");
friends.add("Oliver");

System.out.println("The first element is: " + friends.peekFirst());
System.out.println("The first element is: " + friends.peekLast());

System.out.println(friends);
The first element is: John
The first element is: Oliver
[John, Rob, Greg, Max, Oliver]

Обидва методи повертають перший/останній елемент із черги і не видаляють їх. Якщо черга порожня, буде повернено null.

Загалом якось так, сьогодні ми навчилися працювати з чергами в Java. Тепер ти знатимеш, як їх використовувати на практиці.