理解Java队列接口Queue的设计

时间:2022-06-11
本文章向大家介绍理解Java队列接口Queue的设计,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Queue接口不属于Java并发包下面的类,它是java.util下面的一个接口,虽然这个接口跟并发没有直接关系,但是它抽象和定义了在Java里面队列的通用方法,最重要的是这个类也是Java并发大神Doug Lea设计的,所以学习和了解这个接口是非常有必要的。

Queue队列接口在实现上又继承了Collection接口,而Collection接口又继承了 Iterable接口,所以继承了这两个接口的定义的方法功能,另外Queue接口拥有的直接子类如下:

AbstractQueue
ArrayBlockingQueue
ArrayDeque
ConcurrentLinkedDeque
ConcurrentLinkedQueue
DelayQueue
LinkedBlockingDeque
LinkedBlockingQueue
LinkedList
LinkedTransferQueue
PriorityBlockingQueue
PriorityQueue
SynchronousQueue

但在这里我们重点关注其本身的定义的方法,其本身共定义了6个方法如下:

boolean add(E e) 
boolean offer(E e)
E remove()
E poll()
E element()
E peek()

Queue接口除了具有Collection接口基本的操作能力之外还提供了额外的插入,提取,检查操作,这些操作又分两种形式,第一种如果方法调用失败就会抛出异常,第二种方法调用失败不会抛出异常而会返回一个指定的值,通常是null或者false。第二种的插入设计操作通常是给有界限队列实现的,因为在大多数实现中插入操作不能失败。

我们通过一个表来总结下上面的几个方法:

操作

失败抛出异常

失败返回指定的值

插入

add(e)

offer(e)

移除

remove()

poll()

检查

element()

peek()

在Java的Queue队列接口实现里面,并不是所有的实现都符合队列FIFO先进先出的定义,在其子类实现中PriorityQueue这个优先级队列,就不是按照先进先出设计的,这个类是根据提供的比较器通过对优先级的排序来决定出队的顺序或者根据自然序比较。

此外还有一种LIFO后进先出的队列(或者叫栈),不管使用哪种排序规则,调用remove或者poll方法移除的都是队列头部的元素,在FIFO先进先出队列下,所有新增的节点都会被插入到队列的尾部,其他类型的队列使用不同的处理规则,每个队列的子类实现队列接口时必须指定排序的规则。

offer方法在插入数据失败的时候会返回false,这与Collection.add方法是不一样的,如果add方法添加失败则会抛出对应的异常,offer方法设计的目的是认为当插入失败的时候可以看成这是正常的情况,这就是说允许插入失败,而不抛出异常仅仅返回指定的false,一般用于固定大小(有边界)的队列。

remove和poll方法用来移除和返回队列的头节点,这个移除操作依赖队列的实现类是如何定义其排序规则的,这个在上面提过。这两个方法的不同之处在于当队列是空的时候,remove方法会抛出异常,而poll方法会返回一个null值。

此外element和peek方法会返回队列的头部的节点,但不会移除,可以理解仅仅是偷看一下。

队列接口中没有定义阻塞队列的方法,因为阻塞方法通常是用在并发编程中,这些方法在调用时会如果队列满了或者空了会进入阻塞状态,有关阻塞的队列定义在Queue接口的子类BlockingQueue接口中,这个接口继承了Queue接口。

最后,关于Queue队列的设计,还有两个注意点:

(1)队列的实现通常不允许插入null值,尽管一些队列实现了,如LinkedList就没有禁止,即使LinkedList可以插入null值,但我们在实际使用的时候也不应该向队列插入null值,因为null值通常用于poll方法表示当前队列没有元素了,但如果允许插入null值,这个方法就有歧义,所以我们在使用时候应该避免在队列中插入null值。

(2)队列的实现通常不需要重写该类的equasl和hashCode方法,代替使用Object类默认的定义,因为在队列里面一样的元素可能拥有不同的排序属性。

本文主要主要介绍了Java里面队列的基类接口Queue的设计和相关功能及注意事项,了解了基类接口的相关定义和功能,我们再去学习其下面的各种子类就会比较容易,Queue接口虽然名为队列,但其实这是广泛的定义,队列的底层算法主要是通过链表这种数据结构实现的,虽然也有通过数组的实现的,这也说明了数据结构与算法的重要性,不熟悉的同学,可以先了解一下它们的原理和优缺点。