对于大多数人来说,“队列”这个词在脑海中几乎没有什么愉快的联想。但今天我们谈论的是不同的队列——Java 队列。在 Java 中,队列是继承Queue接口的任何东西,而 Queue 接口又扩展了Collection接口。这意味着队列可以像集合一样对待。

Java 中的队列支持两种操作原则:FIFOLIFO

FIFO (先进先出)原则支配着常规队列——第一个加入队列的元素最先离开

LIFO (后进先出)原则描述了堆栈的行为——最后添加到队列元素最先离开。例如,这就是处理一副纸牌的方式:您一次从最上面的一张纸牌中取出纸牌,直到到达纸牌的底部。

Java 中的队列层次结构如下所示:

这里可以看到Queue有 3 个实现类:LinkedListArrayDequePriorityQueueLinkedListArrayDeque直接继承的不是Queue,而是Deque

Deque是在 Java 6 中添加的接口。它包括几个对队列有用的方法,并允许队列充当双端(或双向)队列。这意味着它可以是FIFOLIFO

Deque接口的两个后代之一是ArrayDeque。它支持双端队列,允许您从两端插入和删除元素。它也是一个自动增长大小的动态数组。

还有一个PriorityQueue类,它是Queue的直接后代:它的行为不同于实现Deque 的类。

PriorityQueue是一个优先级队列,默认情况下根据元素的自然顺序组织元素。这里的排序使用ComparableComparator接口。原理与TreeSetTreeMap相同— 使用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());
}

如果您运行此示例,您将在控制台中看到以下内容:

罗伯
·约翰·
安德鲁

由于我们使用的是队列而不是常规集合,因此我们需要从列表中删除元素。为此,我们使用以下构造:

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

Deque接口继承了Queue方法并添加几个它自己有趣的方法:

void addFirst(E obj) obj元素添加到队列的前面
void addLast(E obj) obj元素添加到队列的末尾
E getFirst() 返回队列中的第一个元素
E getLast() 返回队列中的最后一个元素
boolean offerFirst(E obj) 将obj元素添加到队列的前面,如果添加了元素则返回true 。否则,返回false
布尔报价最后(E obj) 将obj元素添加到队列的末尾,如果添加了元素则返回true 。否则,返回false
E pop() 从队列中获取第一个元素并将其移除
void push(E obj) obj元素添加到队列的前面
E peekFirst() 返回(但不移除)队列中的第一个元素
E peekLast() 返回(但不移除)队列中的最后一个元素
E pollFirst() 返回并移除队列中的第一个元素。如果没有元素,则返回null 。
E pollLast() 返回并移除队列中的最后一个元素。如果没有元素,则返回null 。
E 移除最后一个() 返回并移除队列的第一个元素。如果没有元素则抛出异常。
E removeFirst() 返回并移除队列的最后一个元素。如果没有元素则抛出异常。
布尔 removeFirstOccurrence(对象 obj) 从队列中移除第一次出现的obj
布尔 removeLastOccurrence(对象 obj) 从队列中移除最后一次出现的obj

现在让我们在实践中看看其中的一些方法。

首先,让我们向队列中添加一个元素:

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

        deque.add("Apple"); // Adds "Apple" to the end of the queue
        deque.addFirst("Orange"); // Adds "Orange" to the front of the queue
        deque.addLast("Pineapple"); // Adds "Pineapple" to the end of the queue

        System.out.println(deque);
[橙子、苹果、菠萝]

现在让我们从队列中获取值:

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());

    }

此代码显示队列的第一个和最后一个元素。

第一个元素是:Orange
最后一个元素是:Pineapple

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

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

System.out.println(deque.pop()); // Get and remove the first element of the queue
System.out.println(deque.poll()); // Get and remove the first element of the queue

System.out.println(deque);

运行这段代码,我们得到:


苹果

[菠萝、柠檬]

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()); // Get and remove the first element of the queue
System.out.println(deque.pollLast()); // Get and remove the last element of the queue.
System.out.println(deque);

柠檬
[苹果、菠萝]

这两种方法都返回并从队列中删除一个值。

下面是使用peekFirst()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 last element is: " + friends.peekLast());

System.out.println(friends);
第一个元素是:John
最后一个元素是:Oliver
[John, Rob, Greg, Max, Oliver]

这两种方法都返回队列中的第一个/最后一个元素,并且不删除它们。如果队列为空,则返回null 。

做得好!今天我们学习了如何在 Java 中使用队列。现在您知道如何在实践中使用它们了。