【Java 21 新特性】顺序集合(Sequenced Collections)

1 摘要

引入新的接口表示具有定义的遇到顺序的集合。每个这样的集合都有一个明确定义的第一个元素、第二个元素,依此类推,直到最后一个元素。提供统一的API来访问它的第一个和最后一个元素,并以相反的顺序处理它的元素。

"生活只能向后理解;但必须向前生活。"—基尔克高德

2 动机

Java集合框架缺乏表示具有定义的遇到顺序的元素序列的集合类型。它还缺乏适用于这些集合的统一操作集。这些差距一直是问题和抱怨的重要来源。

如List和Deque都定义了遇到顺序,但共同父类Collection却没有定义遇到顺序。同样,Set没有定义遇到顺序,而子类型HashSet也没定义,但子类型如SortedSet和LinkedHashSet却定义了。因此,对遇到顺序的支持在类型层次结构中分散,使得在API中表达某些有用概念很困难,即不能在Collection中描述具有遇到顺序的参数或返回值。Collection太一般了,将这些约束规定到散文规范中,可能导致难以调试的错误。List太具体了,排除了SortedSet和LinkedHashSet。

FAQ

视图集合通常被迫降级到较弱语义。用Collections::unmodifiableSet包装LinkedHashSet会产生一个Set,丢弃了顺序信息。

没有定义它们的接口,与遇到顺序相关的操作要么不一致,要么缺失。虽许多实现支持获取第一个或最后一个元素,但每个集合都定义了自己的方式,有些不明显或完全缺失:

First elementLast element
Listlist.get(0)list.get(list.size() - 1)
Dequedeque.getFirst()deque.getLast()
SortedSetsortedSet.first()sortedSet.last()
LinkedHashSetlinkedHashSet.iterator().next()// missing
  • 一些是不必要的繁琐,如获取List的最后一个元素
  • 有些甚至没有英雄主义是不可能的:获取LinkedHashSet的最后一个元素的唯一方法是迭代整个集合!
  • 同样,从第一个元素到最后一个元素遍历通常需用迭代器或使用普通for循环,使代码冗长不直观

为解决这些问题,引入新接口SequencedCollection表示具有定义的遇到顺序的集合。每个SequencedCollection都有一个明确定义的第一个元素、第二个元素,依此类推,直到最后一个元素。它还提供统一的API访问它的第一个和最后一个元素,并以相反的顺序处理它的元素。

SequencedCollection还提供新reversed()方法,提供一个反向排序的视图。这视图可让集合以相反顺序处理元素,使用所有常见迭代机制,如增强for循环、显式的iterator()循环、forEach()、stream()、parallelStream()和toArray()。

如以前从LinkedHashSet获取反向排序的流困难,现只需linkedHashSet.reversed().stream()。

SequencedCollection还从Deque中提升一些方法,支持在两端添加、获取和删除元素:

  • void addFirst(E)
  • void addLast(E)
  • E getFirst()
  • E getLast()
  • E removeFirst()
  • E removeLast()

add(E)和remove()方法可选,主要是为支持不可修改的集合的情况。如集合为空,get()和remove()方法将抛出NoSuchElementException。

由于SequencedCollection的子接口具有冲突的定义,所以在SequencedCollection中没有定义equals()和hashCode()方法。

这些改动使得具有遇到顺序的集合更加易于使用和操作,并提供了一致的API来处理这些集合的元素。

Sequenced Sets

Set接口的扩展,有序集合,不含重复元素:

// since 21
interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {SequencedSet<E> reversed();    // 协变重写
}

SequencedSet接口提供reversed()方法,用于返回一个反转顺序的SequencedSet。对于LinkedHashSet等集合,若元素已存在于集合中,则会将其移动到适当位置。这解决LinkedHashSet无法重新定位元素痛点。

SequencedMap

Map接口的扩展,条目具有定义好的遍历顺序。

interface SequencedMap<K,V> extends Map<K,V> {// 新方法SequencedMap<K,V> reversed();SequencedSet<K> sequencedKeySet();SequencedCollection<V> sequencedValues();SequencedSet<Entry<K,V>> sequencedEntrySet();V putFirst(K, V);V putLast(K, V);// 从NavigableMap中提升的方法Entry<K, V> firstEntry();Entry<K, V> lastEntry();Entry<K, V> pollFirstEntry();Entry<K, V> pollLastEntry();
}
  • reversed()返回一个反转顺序的SequencedMap
  • sequencedKeySet()返回一个有序的键集合
  • sequencedValues()返回一个有序的值集合
  • sequencedEntrySet()返回一个有序的条目集合

SequencedMap还提供了putFirst()和putLast()方法,用于在指定位置插入键值对。对于SortedMap等映射,这些方法会抛出UnsupportedOperationException。

SequencedMap还提升了一些方法从NavigableMap接口,这些方法支持在两端获取和删除条目。

Retrofitting

为了将新的接口与现有的类和接口结构整合起来,调整:

img

  • List接口现在直接继承自SequencedCollection接口
  • Deque接口现在直接继承自SequencedCollection接口
  • LinkedHashSet类实现了SequencedSet接口
  • SortedSet接口现在直接继承自SequencedSet接口
  • LinkedHashMap类实现了SequencedMap接口
  • SortedMap接口现在直接继承自SequencedMap接口。

在适当的位置为reversed()方法提供了协变重写。如List#reversed()重写为返回一个List类型的值,而不是SequencedCollection类型的值。

还在Collections工具类中添加了一些新的方法,用于创建不可修改的包装器:

  • Collections.unmodifiableSequencedCollection(sequencedCollection)
  • Collections.unmodifiableSequencedSet(sequencedSet)
  • Collections.unmodifiableSequencedMap(sequencedMap)

替代方案

类型

将List接口重新定义为通用的有序集合类型。虽然List是有序的,但它也支持通过整数索引访问元素。许多有序的数据结构并不自然地支持索引,因此它们将被要求通过迭代来支持索引访问,这将导致索引访问的性能从O(1)变为O(n),延续了LinkedList的错误。

Deque作为通用的序列类型似乎是一个不错的选择,因为它已经支持了正确的一组操作。然而,它还包含了其他操作,包括一系列返回null的操作(offer、peek和poll),以及从Queue继承的操作。这些操作对于队列来说是合理的,但对于其他集合来说则不太合适。如果将Deque重新定义为通用的序列类型,那么List也将成为一个Queue,并支持栈操作,导致API变得混乱和令人困惑。

命名

术语"sequence"(序列)在这里被选择,它暗示了元素按照一定的顺序排列。它在各个平台上都被广泛使用,表示具有类似语义的集合。

术语"ordered"(有序)并不够具体。我们需要迭代两个方向上的元素,并在两端进行操作。一个有序的集合,如Queue,是一个明显的例外:它是有序的,但它也明显是不对称的。

术语"reversible"(可逆)在之前的版本中使用过,但它并没有立即唤起双端的概念。也许更大的问题是,Map变体将被命名为ReversibleMap,这会误导地暗示它支持通过键和值进行查找(有时称为BiMap或BidiMap)。

Add, put, and UnsupportedOperationException

对于通过相对比较确定顺序的集合,例如SortedSet的addFirst和SortedMap的putLast方法会抛出UnsupportedOperationException。一些集合不实现所有SequencedCollection操作的不对称性可能看起来不太好。然而,这是有价值的,因为它将SortedSet和SortedMap纳入到有序集合的家族中,使它们可以比以前更广泛地使用。这种不对称性也与集合框架中的先前设计决策保持一致。例如,Map的keySet方法返回一个Set,即使实际返回的实现不支持添加操作。

另一种方法是通过重新调整接口来保持添加操作的独立性。这将导致在结构上有很薄的语义的新接口类型(例如AddableCollection),在实践中没有用处,并且会使类型层次结构变得混乱。

测试

我们将在JDK的回归测试套件中添加一套全面的测试。

风险和假设

在继承层次结构中高层次地引入新的方法可能会导致对明显方法名称(如reversed()和getFirst())的冲突。

特别需要关注的是List和Deque上reversed()方法的协变重写。这些重写与已经实现了List和Deque的现有集合在源代码和二进制兼容性上是不兼容的。在JDK中有两个这样的集合的例子:LinkedList和一个内部类sun.awt.util.IdentityLinkedList。LinkedList类通过在LinkedList本身上引入一个新的reversed()协变重写来处理。内部的IdentityLinkedList类被删除,因为它不再需要。

提案的早期版本在SequencedMap接口上引入了keySet()、values()和entrySet()方法的协变重写。经过一些分析,确定这种方法引入了不兼容性的风险太大;实际上,它使任何现有的子类都无效。选择了另一种方法,即在SequencedMap中引入了新的sequencedKeySet()、sequencedValues()和sequencedEntrySet()方法,而不是调整现有方法为协变重写。回顾起来,这可能是因为在Java 6中引入navigableKeySet()方法时采用了类似的方法,而不是修改现有的keySet()方法为协变重写。

有关不兼容性风险的完整分析,请参见附加到CSR(JDK-8266572)的报告。

历史

这个提案是我们2021年ReversibleCollections提案的一个增量演进。与该提案相比,主要的变化是改名、引入SequencedMap接口以及引入不可修改的包装器方法。

ReversibleCollection提案又基于Tagir Valeev的2020年OrderedMap/OrderedSet提案。该提案中的一些基本概念仍然存在,尽管在细节上有很多不同。

多年来,我们收到了许多关于将List与Set或Map结合的请求和提案。这些请求包括4152834、4245809、4264420、4268146、6447049和8037382。

其中一些请求在Java 1.4中引入的LinkedHashSet和LinkedHashMap中部分得到了满足。虽然这些类满足了一些用例,但它们的引入留下了集合框架中抽象和操作的空白,如上所述。

测试

我们将向JDK的回归测试套件中添加一套全面的测试。

风险和假设

在继承层次结构中引入新的方法存在冲突的风险,例如reversed()和getFirst()这样的明显方法名称。 特别关注的是List和Deque上的covariant overrides的reversed()方法。这些方法与已实现List和Deque的现有集合在源代码和二进制上不兼容。在JDK中有两个这样的集合的示例:LinkedList和一个内部类sun.awt.util.IdentityLinkedList。LinkedList类通过在LinkedList本身上引入了一个新的reversed() covariant override来处理。内部的IdentityLinkedList类被删除,因为它不再需要。 提案的早期版本在SequencedMap接口的keySet()、values()和entrySet()方法上引入了covariant overrides。经过一些分析,确定这种方法引入了太大的不兼容风险;实质上,它使任何现有的子类无效。选择了另一种替代方法,即在SequencedMap中引入新的方法sequencedKeySet()、sequencedValues()和sequencedEntrySet(),而不是调整现有方法为covariant overrides。回顾起来,可能出于同样的原因,在Java 6中引入navigableKeySet()方法时采取了类似的方法,而不是修改现有的keySet()方法为covariant override。 有关不兼容风险的完整分析,请参阅附加到CSR(JDK-8266572)的报告。

参考

  • 编程严选网专栏-JDK21新特性

    本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/315140.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业签名分发对移动应用开发者有什么影响

企业签名分发是移动应用开发者在应用程序发布前测试、内部分发和特定的受众群体分发等方面比较常用的一种工具。那对于应用商城分发有啥区别&#xff0c;下面简单的探讨一下。 独立分发能力 通过企业签名分发开发者可以自己决定应用程序的发布时间和方式&#xff0c;不用受应用…

使用Wireshark进行网络流量分析

目录 Wireshark是什么&#xff1f; 数据包筛选 筛选指定ip 使用逻辑运算符筛选 HTTP模式过滤 端口筛选 协议筛选 包长度筛选 数据包搜索 数据流分析 数据包导出 Wireshark是什么&#xff1f; 通过Wireshark&#xff0c;我们可以捕获和分析网络数据包&#xff0c;查看…

项目管理流程指南:分解阶段

项目管理流程是项目管理始终不变的一个方面&#xff0c;尤其在瀑布式方法中。 项目管理协会&#xff08;PMI&#xff09;将这一流程定义为五个不同的阶段&#xff1a;启动、计划、执行、监控和收尾。这五个阶段已在全球范围内得到广泛认可和接受。下面来了解如何完成每个阶段&…

学生数据可视化与分析工具 vue3+flask实现

目录 一、技术栈亮点 二、功能特点 三、应用场景 四、结语 学生数据可视化与分析工具介绍 在当今的教育领域&#xff0c;数据驱动的决策正变得越来越重要。为了满足学校、教师和学生对于数据深度洞察的需求&#xff0c;我们推出了一款基于Vue3和Flask编写的学生数据可视化…

牛客周赛 Round 26 解题报告 | 珂学家 | 0-1 BFS + 状态机DP

前言 整体评价 T3是一道0-1 BFS题, 这样时间复杂度可以控制在O(n*m), 也可以用优先队列。 T4这类题型&#xff0c;在牛客Round周赛系列出现好多次了&#xff0c;要么状态机DP&#xff0c;要么容斥&#xff0c;如果n很大&#xff0c;就用矩阵幂优化。 欢迎关注 珂朵莉 牛客周…

LiveGBS流媒体平台GB/T28181常见问题-如何配置快照目录快照存储默认目录目录如何配置

LiveGBS流媒体平台GB/T28181常见问题-如何配置快照目录快照存储默认目录目录如何配置 1、快照目录2、指定快照目录3、搭建GB28181视频直播平台 1、快照目录 部署LiveGBS后&#xff0c; 再查看通道播放后 或是 获取通道快照后&#xff0c;就会在LiveSMS部署的服务器里面存储对应…

学Python到底能干什么?看这里就知道

学Python到底能干什么&#xff1f;看这里就知道 | Python是一种代表简单主义思想的语言&#xff0c;极其容易上手&#xff0c;并且功能非常强大&#xff0c;这也是我的第二计算机语言。 个人可以使用Python去做哪些事呢&#xff1f; ✅办公自动化场景&#xff1a; 每天要处理…

南昌找工作用什么APP或者招聘网站

南昌找工作用吉鹿力招聘网 通过吉鹿力招聘网&#xff0c;可以随时查看最新职位&#xff0c;跟踪简历投递动态&#xff0c;与正在进行招聘的CEO、部门负责人、HR在线沟通&#xff0c;查看其他候选人面试该职位后对面试官、公司环境的面试评价等&#xff0c;为求职者提供参考。 …

2024 年 9 款简单好用的 Windows 分区管理器软件

了解适用于 Windows 11 和 Windows 7 的 Windows 分区管理器的概念。本教程还列出了分区管理器软件&#xff1a; 购买新电脑&#xff1f;担心磁盘存储空间不足&#xff1f;你听说过分区吗&#xff1f;如果没有&#xff0c;这篇文章就是为你准备的。 在本文中&#xff0c;我们…

ABAQUS应用03——装配以及对应的Python代码

文章目录 0. 背景1、一般情况下零件的装配及定位约束2、混塔节段的装配 0. 背景 本文为ABAQUS应用的系列文章&#xff0c;主要依托本人工作中的实际应用&#xff0c;方便学习记录ABAQUS&#xff0c;所以并不会太多考虑读者的阅读效果&#xff0c;这里请各位见谅。 ABAQUS学习的…

【LeetCode】20. 有效的括号(Deque的Stack用法)

今日学习的文章链接和视频链接 leetcode题目地址&#xff1a;20. 有效的括号 代码随想录题解地址&#xff1a;代码随想录 题目简介 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效…

除了文件助手还能怎么传文件?便签快速实文件共享

在日常生活和工作中&#xff0c;我们经常遇到需要传输或不同设备共享文件的情况。每当这时&#xff0c;很多人首先想到的是使用文件助手&#xff0c;它确实提供了便捷的文件传输服务。但是&#xff0c;我也曾担忧过它的安全性&#xff0c;特别是在使用陌生电脑时&#xff0c;我…