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

这篇具有很好参考价值的文章主要介绍了【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 element Last element
List list.get(0) list.get(list.size() - 1)
Deque deque.getFirst() deque.getLast()
SortedSet sortedSet.first() sortedSet.last()
LinkedHashSet linkedHashSet.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

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

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

  • 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 发布!文章来源地址https://www.toymoban.com/news/detail-771488.html

到了这里,关于【Java 21 新特性】顺序集合(Sequenced Collections)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java02-迭代器,数据结构,List,Set ,TreeSet集合,Collections工具类

    目录 什么是遍历? 一、Collection集合的遍历方式 1.迭代器遍历 方法 流程 案例 2. foreach(增强for循环)遍历 案例 3.Lamdba表达式遍历 案例 二、数据结构 数据结构介绍 常见数据结构 栈(Stack) 队列(Queue) 链表(Link) 散列表(Hash Table) 树(Tree) List接口 ArraysList集合 Linked

    2024年02月14日
    浏览(34)
  • JDK21:Java21的新特性

    定于9月推出的Java21计划现在包括一个关键封装机制API和32位Windows端口的弃用。 Java开发工具包(JDK)21将于9月作为Oracle标准Java实现的下一个长期支持版本,现在有13个功能被正式提出,最近几天又增加了两个功能。 最新的提议包括密钥封装机制(KEM)API和32位x86 Windows端口的

    2024年02月07日
    浏览(33)
  • Java 21即将发布,探索Java 21新特性和改进

    Java 21是 Java 17之后的下一个 LTS版本。虚拟线程在 Java 21中将成为正式功能。Java 21 有望将会成为继 java8 之后又一个流行的 Java 版本。 Java 21将在 2023 年 9 月 19 日发布 3.1 正式功能 虚拟线程 (Virtual Threads) 顺序集合(Sequenced Collections) 记录类型的模式(Record Patterns) switch 的模

    2024年02月07日
    浏览(36)
  • Java21 新特性

    2023年9月19日 ,Oracle 发布了 JDK21,是自 JDK17 之后最新的 LTS 版本(long-term support,长期支持版)。LTS版本一般每两年发布一个,JDK目前的LTS版本有:JDK8 , JDK11 , JDK17 ,JDK21。 Java21新特性:( oracle jdk、openjdk文档) 字符串模板(预览版) 虚拟线程(在JDK19中是预览版,在JDK21中是

    2024年02月03日
    浏览(49)
  • Java 21 新特性和改进

    Java 21 是 Java 17 之后的下一个 LTS 版本。虚拟线程在 Java 21 中将成为正式功能。可以预期的是,Java 21 会成为一个很流行的 Java 版本。 Java 21 将在 2023 年 9 月 19 日发布。目前 Java 21 包含的内容已经基本确定了。下面来梳理一下 Java 21 中会包含的内容。 虚拟线程 (Virtual Threads)

    2024年02月07日
    浏览(28)
  • Java 21 新特性(LTS版本)

    JDK 21 于 2023 年 9 月 19 日 发布,这是一个非常重要的版本,里程碑式。 JDK21 是 LTS(长期支持版),至此为止,目前有 JDK8、JDK11、JDK17 和 JDK21 这四个长期支持版了。 官方文档:OpenJDK Java 21 文档 Java各个版本的文档入口:Java平台,标准版文档 Java各个版本下载:https://jdk.java

    2024年04月23日
    浏览(32)
  • Java 21新特性-虚拟线程 审核中

    本文翻译自国外论坛 medium,原文地址:https://medium.com/@benweidig/looking-at-java-21-virtual-threads-0ddda4ac1be1 Java 21 版本更新中最重要的功能之一就是虚拟线程 (JEP 444)。这些轻量级线程减少了编写、维护和观察高吞吐量并发应用程序所需的工作量。 正如我的许多其他文章一样,在推出

    2024年02月08日
    浏览(44)
  • 【Java基础系列】JDK21新特性

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年02月04日
    浏览(33)
  • Java 21 新特性:Record Patterns

    Record Patterns 第一次发布预览是在JDK 19、随后又在JDK 20中进行了完善。现在,Java 21开始正式推出该特性优化。下面我们通过一个例子来理解这个新特性。 上述代码中定义了一个名为Point的record类(Java 16中的新特性),如果我们想要获取、操作或者打印Point中的x和y的话。就不得

    2024年02月08日
    浏览(37)
  • Java 21:最新特性、性能改进和语言发展

    🎉欢迎来到Java学习路线专栏~Java 21:最新特性、性能改进和语言发展 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:Java学习路线 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有

    2024年02月05日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包