Java队列 – Java中的队列

Java队列是在java.util包中提供的一个接口,它扩展了java.util.Collection接口。就像Java列表一样,Java队列是一个有序元素(或对象)的集合,但它执行插入和删除操作的方式不同。我们可以使用队列在处理这些元素之前存储它们。

Java队列

在本节中,我们将讨论关于Java队列的一些重要点:

  • java.util.Queue接口是java.util.Collection接口的子类型。
  • 就像现实生活中的队列(例如,在银行或ATM中),队列将元素插入队列的末尾并从队列的开头删除。
  • Java队列表示一个有序的元素列表。
  • Java队列遵循FIFO顺序插入和删除其元素。FIFO代表先进先出。
  • Java队列支持Collection接口的所有方法。
  • 最常用的队列实现是LinkedList、ArrayBlockingQueue和PriorityQueue。
  • BlockingQueues不接受null元素。如果执行任何与null相关的操作,它会抛出NullPointerException。
  • BlockingQueues用于实现基于生产者/消费者的应用程序。
  • BlockingQueues是线程安全的。
  • 所有在java.util包中可用的队列都是无界队列,而在java.util.concurrent包中可用的队列是有界队列。
  • 所有双端队列都不是线程安全的。
  • ConcurrentLinkedQueue是基于链接节点的无界线程安全队列。
  • 所有队列都支持在队列尾部插入和在队列头部移除,除了双端队列。
  • 双端队列是队列,但它们支持在两端插入和移除元素。

Java队列类图

Java Queue接口扩展了Collection接口。Collection接口扩展了Iterable接口。一些常用的队列实现类包括LinkedList,PriorityQueue,ArrayBlockingQueue,DelayQueue,LinkedBlockingQueue,PriorityBlockingQueue等。AbstractQueue提供了Queue接口的骨架实现,以减少实现Queue的工作量。

Java队列方法

在本节中,我们将讨论一些有用且经常使用的Java队列方法:

  1. int size(): 获取集合中元素的数量。
  2. boolean isEmpty(): 检查集合是否为空。
  3. boolean contains(Object o): 如果此集合包含指定的元素,则返回 true。
  4. Iterator iterator(): 返回该集合中元素的迭代器。元素以无特定顺序返回。
  5. boolean removeAll(Collection c): 从该集合中移除包含在指定集合中的所有元素(可选操作)。
  6. boolean retainAll(Collection c): 仅保留在该集合中包含在指定集合中的元素(可选操作)。
  7. void clear(): 从集合中移除所有元素。
  8. E remove(): Retrieves and removes the head of this queue.
  9. E poll(): Retrieves and removes the head of this queue, or returns null if this queue is empty.
  10. E peek(): Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty.
  11. boolean offer(E e): 如果可以在不违反容量限制的情况下立即将指定元素插入此队列,则插入并返回 true。
  12. E element(): Retrieves, but does not remove, the head of this queue.
  13. boolean add(E e): 如果可以在不违反容量限制的情况下立即将指定元素插入此队列,则插入并在成功时返回 true;如果当前没有可用空间,则抛出 IllegalStateException。
  14. Object[] toArray(): 返回包含此集合中所有元素的数组。如果此集合对其迭代器返回的元素顺序有任何保证,该方法必须以相同顺序返回元素。

Java 队列基础

由于Java队列扩展了Java集合,因此它也支持所有集合接口操作。让我们在下面的示例中探索一些简单的操作:

package com.journaldev.queue;
import java.util.*;

public class QueueExample {
   public static void main(String[] args) {
		
	Queue queue = new LinkedList<>();
	queue.add("one");
	queue.add("two");
	queue.add("three");
	queue.add("four");
	System.out.println(queue);
		
	queue.remove("three");
	System.out.println(queue);
	System.out.println("Queue Size: " + queue.size());
	System.out.println("Queue Contains element 'two' or not? : " + queue.contains("two"));

	// 清空队列
	queue.clear();
   }
}

输出:-

[one, two, three, four]
[one, two, four]
Queue Size: 3
Queue Contains element 'two' or not? : true

Java数组转换为队列

在这里,我们可以通过一个简单的示例来探索如何使用“Collections.addAll()”方法将Java数组转换为队列。

import java.util.*;

public class ArrayToQueue {
    public static void main(String[] args) {
		
	String nums[] = {"one","two","three","four","five"};
	Queue<String> queue = new LinkedList<>();
	Collections.addAll(queue, nums);
	System.out.println(queue);
   }
}

输出:-当我们运行上述程序时,我们将获得以下输出:

[one, two, three, four, five]

Java队列转换为数组

在这里,我们将通过一个简单的示例来探索如何使用“toArray()”将Java队列转换为Java数组。

import java.util.*;

public class QueueToArray {
   public static void main(String[] args) {
		
	Queue<String> queue = new LinkedList<>();
	queue.add("one");
	queue.add("two");
	queue.add("three");
	queue.add("four");
	queue.add("five");
		
	String strArray[] = queue.toArray(new String[queue.size()]);
	System.out.println(Arrays.toString(strArray)); 

   }
}

输出:-当我们运行上述程序时,我们将获得以下输出:

[one, two, three, four, five]

Java队列常见操作

Java队列支持集合接口支持的所有操作以及一些额外的操作。它以两种形式支持几乎所有操作。

  • 一组操作在操作失败时抛出异常。
  • 另一组操作在操作失败时返回特殊值。

以下表格简要解释了所有队列的常见操作。

Operation Throws exception Special value
Insert add(e) offer(e)
Remove remove() poll()
Examine element() peek()

我们将逐个讨论每个操作,并在接下来的部分中详细讨论它们,附带一些有用的示例。

Java队列插入操作

在本节中,我们将详细讨论Java队列插入操作,并附带一些有用的示例。如果此操作执行成功,它将返回“true”值。正如我们所知,队列支持两种形式的插入操作:

  • Queue.add(e):
    如果操作失败,它会抛出异常。- Queue.offer(e):
    如果操作失败,它将返回一个特殊值。

注意: 这里的特殊值可以是“false”或“null”

队列add()操作

add()操作用于将新元素插入队列。如果成功执行插入操作,它将返回“true”值。否则,它会抛出java.lang.IllegalStateException。让我们开发一个简单的示例来演示此功能。

import java.util.concurrent.*;

public class QueueAddOperation {
   public static void main(String[] args) {
		
	BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);

	System.out.println(queue.add("one"));
	System.out.println(queue.add("two"));
	System.out.println(queue);
	System.out.println(queue.add("three"));
	System.out.println(queue);
   }
}

当我们运行以上程序时,我们将得到以下输出:

true
true
[one, two]
Exception in thread "main" java.lang.IllegalStateException: Queue full

由于我们的队列限制为两个元素,当我们尝试使用BlockingQueue.add()添加第三个元素时,它会抛出异常,如上所示。

队列offer()操作

offer()操作用于向队列插入新元素。如果成功执行插入操作,则返回“true”值。否则返回“false”值。让我们开发一个简单的示例来演示这个功能。

import java.util.concurrent.*;

public class QueueOfferOperation {
   public static void main(String[] args) {
		
	BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);

	System.out.println(queue.offer("one"));
	System.out.println(queue.offer("two"));
	System.out.println(queue);
	System.out.println(queue.offer("three"));
	System.out.println(queue);
   }
}

输出:当我们运行以上程序时,我们将得到以下输出:

true
true
[one, two]
false
[one, two]

由于我们的队列限制为两个元素,当我们尝试使用BlockingQueue.offer()操作添加第三个元素时,它会返回“false”值,如上所示。

Java队列删除操作

在本节中,我们将详细讨论Java队列删除操作,并提供一些有用的示例。如果删除操作成功执行,则返回队列的头元素。正如我们所知,队列支持两种形式的删除操作:

  • Queue.remove():如果操作失败,则抛出异常。- Queue.poll():如果操作失败,则返回一个特殊值。

注意:- 这里特殊值可以是“false”或“null”

队列 remove() 操作

remove() 操作用于从队列头部删除一个元素。如果成功执行删除操作,它将返回队列的头元素。否则,它会抛出 java.util.NoSuchElementException 异常。让我们开发一个简单的示例来演示这个功能。

import java.util.*;

public class QueueRemoveOperation 
{
   public static void main(String[] args) 
   {		
	Queue<String> queue = new LinkedList<>();
	queue.offer("one");
	queue.offer("two");		
	System.out.println(queue);		
	System.out.println(queue.remove());
	System.out.println(queue.remove());		
	System.out.println(queue.remove());		
   }
}

输出:当我们运行上面的程序时,将得到以下输出:

[one, two]
one
two
Exception in thread "main" java.util.NoSuchElementException

由于我们的队列只有两个元素,当我们尝试第三次调用 remove() 方法时,它会抛出如上所示的异常。注意:- Queue.remove(element) 用于从队列中删除指定的元素。如果成功执行删除操作,它将返回“true”值。否则,它将返回“false”值。

队列 poll() 操作

poll() 操作用于从队列头部删除一个元素。如果成功执行删除操作,它将返回队列的头元素。否则,它将返回“null”值。让我们开发一个简单的示例来演示这个功能。

import java.util.*;

public class QueuePollOperation 
{
   public static void main(String[] args) 
   {		
	Queue<String> queue = new LinkedList<>();
	queue.offer("one");
	queue.offer("two");		
	System.out.println(queue);		
	System.out.println(queue.poll());
	System.out.println(queue.poll());		
	System.out.println(queue.poll());		
   }
}

输出:-当我们运行以上程序时,我们将得到以下输出:

[one, two]
one
two
null

由于我们的队列只有两个元素,当我们尝试第三次调用poll()方法时,它会返回null值,如上所示。

Java队列检查操作

在本节中,我们将详细讨论Java队列检查操作,并附带一些有用的示例。如果此操作成功执行,它将返回队列的头元素,而不将其移除。正如我们所知,队列支持两种形式的检查操作:

  • Queue.element():
    如果操作失败,它会抛出异常。- Queue.peek():
    如果操作失败,它将返回一个特殊值。

注意:-这里的特殊值可以是“false”或“null”

队列element()操作

element()操作用于从队列头部检索元素,而不将其移除。如果成功执行检查操作,它将返回队列的头元素。否则,它会抛出java.util.NoSuchElementException异常。让我们开发一个简单的示例来演示这个功能。

import java.util.*;

public class QueueElementOperation {
   public static void main(String[] args) {
		
	Queue<String> queue = new LinkedList<>();
	queue.add("one");
		
	System.out.println(queue.element());
	System.out.println(queue);
	queue.clear();
	System.out.println(queue.element());
   }
}

输出:-当我们运行以上程序时,我们将得到以下输出:

one
[one]
Exception in thread "main" java.util.NoSuchElementException

如果我们尝试在空队列上调用element()方法,它会抛出异常,如上所示。

队列 peek() 操作

peek() 操作用于从队列头部检索元素,但不移除它。如果成功执行检查操作,则返回队列头部的元素。否则返回 null 值。让我们开发一个简单的示例来演示这个功能。

import java.util.*;

public class QueuePeekOperation {
   public static void main(String[] args) {
		
	Queue<String> queue = new LinkedList<>();
	queue.add("one");
		
	System.out.println(queue.peek());
	System.out.println(queue);
	queue.clear();
	System.out.println(queue.peek());
   }
}

输出:-当我们运行上述程序时,我们将得到以下输出:

one
[one]
null

如果我们尝试在空队列上调用peek()方法,它会返回null值,但不会像上面所示抛出异常。

Java队列分类

在Java中,我们可以找到许多队列实现。我们可以将它们大致分类为以下两种类型:

  • 有界队列
  • 无界队列

有界队列是在创建时通过容量限制的队列,这意味着我们需要提供队列的最大大小。例如,ArrayBlockingQueue(见前面的例子)。无界队列是没有容量限制的队列,这意味着我们不应该提供队列的大小。例如,LinkedList(见前面的例子)。java.util包中可用的所有队列都是无界队列,而java.util.concurrent包中可用的队列都是有界队列。换句话说,我们可以广泛将它们分为以下两种类型:

  • 阻塞队列
  • 非阻塞队列

所有实现BlockingQueue接口的队列都是阻塞队列,其余的是非阻塞队列。阻塞队列会阻塞,直到完成任务或超时,而非阻塞队列则不会。一些队列是双端队列,而一些队列是优先队列。

阻塞队列操作

除了队列的两种操作形式外,阻塞队列还支持下面显示的两种形式的操作。

Operation Throws exception Special value Blocks Times out
Insert add(e) offer(e) put(e) offer(e, time, unit)
Remove remove() poll() take() poll(time, unit)
Examine element() peek() N/A N/A

一些操作会阻塞,直到完成任务,而另一些操作会阻塞,直到超时。这就是关于Java中队列的一个快速概述。希望这些Java队列示例能帮助你开始使用队列集合编程。如果你喜欢我的教程或有任何建议、问题或打字错误,请给我留言。谢谢。

Source:
https://www.digitalocean.com/community/tutorials/java-queue