理解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接口虽然名为队列,但其实这是广泛的定义,队列的底层算法主要是通过链表这种数据结构实现的,虽然也有通过数组的实现的,这也说明了数据结构与算法的重要性,不熟悉的同学,可以先了解一下它们的原理和优缺点。
- “协变”、“逆变”与Delegate类型转换
- 如今的人工智能是不是真的已经很聪明了?
- 【Scikit-Learn 中文文档】聚类 - 无监督学习 - 用户指南 | ApacheCN
- Delegate如何进行类型转换?
- 个性化推荐系统(一)---今日头条等的内容划分、分类
- ASP.NET Core的配置(2):配置模型详解
- 如何解决jQuery Validation针对动态添加的表单无法工作的问题?
- 数据结构 链表改进
- 数据结构 栈&队列
- 终端品牌域名过期被拍卖 价值六位数
- TensorFlow 深度学习笔记 TensorFlow实现与优化深度神经网络
- ASP.NET的路由系统:路由映射
- ASP.NET Core的配置(3): 将配置绑定为对象[上篇]
- ASP.NET的路由系统:URL与物理文件的分离
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- expect命令在linux下实现批量ssh免密
- 学习Vim合并行的方法和技巧
- 九种查找算法
- 代码防御性编程的十条技巧
- Ubuntu终端多窗口分屏Terminator
- linux 编译安装python3.6的教程详解
- Unix/Linux系统下的nobody用户与nologin详细介绍
- 详解flutter engine 那些没被释放的东西
- Centos7安装PHP及Nginx的教程详解
- Flutter Image实现图片加载
- Centos7系统下搭建.NET Core2.0+Nginx+Supervisor环境
- CentOS7 LNMP+phpmyadmin环境搭建 第二篇LNMP环境搭建教程
- 详解Linux 下开发微信小程序安装开发工具
- Linux一个增强的截图及分享工具:ScreenCloud
- linux 命名管道实例详解