JDK 10 中的不可变与不可修改

位置:首页>文章>详情   分类: Java教程 > 编程技术   阅读(97)   2024-06-16 06:20:10

将近两个月前,Stuart Marks 写道,“不变性就像酒。”然后他提醒读者叔本华的熵定律:“如果你把一勺酒放在装满污水的桶里,你就会得到污水。如果将一勺污水倒入装满酒的桶中,就会得到污水。”在提供的背景下,Marks 将叔本华的熵定律应用于不变性,用“不变性”代替“酒”,用“可变性”代替“污水”,做出了这一富有洞察力的观察:

同样,如果你给可变的东西增加一点不可变性,你就会得到可变性。如果你给不可变的东西增加一点可变性,你就会得到可变性。

这段引文的上下文是从 10 月开始的在线讨论,内容涉及针对 JDK 10 的 JDK-8177290(“为不可修改的 List、Set、Map 添加复制工厂方法”)和JDK-8184690(“将收集器添加到不可修改的 List、Set 和 Map 中”)。 JDK-8177290 是 JDK-8156070(“不可变集合增强”)的子任务,它被描述为“不可变集合的各种增强和改进子任务的容器”。讨论相当冗长,涉及多种且通常截然不同的观点,涉及诸如“不可变”和“不可修改”等术语。事实上,在本次讨论的第一篇文章中,Mark 写道,“在数据结构方面,术语‘immutable’与‘persistent’密不可分,我相信如果 Java 的‘不可变’意味着与其他人不同的东西,我们将永远解释这一点。”

可以在与 JDK-8191517 相关的当前文本(“为不可修改的 List、Set、Map 添加复制工厂方法”)中找到指向最终确定要使用的术语的指针。此文本包含此声明,“提供‘视图’集合、‘不可修改’集合和‘不可修改视图’集合的定义。” JDK-8191517 还引用了 webrev.4.zipspecdiff.4.zip 以获取更多底层细节。这篇文章的其余部分将查看那些引用的 ZIP 文件中记录的一些低级详细信息。

在引用的 zip 文件中添加到选择接口源代码的 Javadoc 注释包含有关术语“'view' collections”、“'unmodifiable' collections”和“‘不可修改的视图’集合。”例如,java.util.Collection 的 Javadoc 在其接口级 Javadoc 注释中添加了以下描述:

  • 查看集合”——“大多数集合管理它们包含的元素的存储。相比之下,视图集合 本身不存储元素,而是依赖后备集合来存储实际元素。视图集合本身不处理的操作委托给后备集合。”
    • 关于修改:“对支持集合所做的任何更改都在视图集合中可见。相应地,对视图集合所做的任何更改(如果允许更改)都会写入支持集合”
    • 示例:“由 Collections.checkedCollectionCollections.synchronizedCollectionCollections.unmodifiableCollection 等方法返回的包装集合”
    • 更多示例:“为相同元素提供不同表示的集合”,例如“List.subListNavigableSet.subSetMap.entrySet
  • 不可修改的集合”——“一个不可修改的集合是一个集合,它的所有修改器方法……都被指定为抛出 UnsupportedOperationException。这样的集合因此不能通过调用其上的任何方法来修改。为了使集合正确不可修改,从它派生的任何视图集合也必须是不可修改的。”
    • 关于修改:“不可修改的集合不一定是不可变的。如果包含的元素是可变的,那么整个集合显然是可变的,即使它可能是不可修改的。 ……但是,如果一个不可修改的集合包含所有不可变元素,则可以认为它实际上是不可变的。”
  • 不可修改的视图集合”——“不可修改的视图集合是不可修改的集合,也是支持集合的视图。它的 mutator 方法抛出 UnsupportedOperationException},如上所述,而读取和查询方法被委托给后备集合。效果是提供对后备集合的只读访问。”
    • 关于修改:“请注意,对后备集合的更改可能仍然是可能的,如果发生,它们通过不可修改的视图是可见的。因此,不可修改的视图集合不一定是不可变的。但是,如果不可修改视图的后备集合实际上是不可变的,或者如果对后备集合的唯一引用是通过不可修改视图,则可以认为该视图是有效不可变的。”
    • 示例:“[集合] 由 Collections.unmodifiableCollection [和] Collections.unmodifiableList 返回。”

上面的项目符号详细查看了为 java.util.Collection 类添加到 Javadoc 的注释,但是其他集合接口的 Javadoc 注释也有关于与那些特定接口相关的不变性和不可修改性的重要新注释。例如,先前引用的 ZIP 文件中显示的 java.util.List 接口 Javadoc 注释讨论了“不可修改的列表”、可用于访问此类 List 的便利机制以及 List的特征 通过这些机制检索。 java.util.Setjava.util.Map 接口的 Javadoc 注释接受类似的处理。

到目前为止,我主要关注如何增强 Javadoc 文档以及如何将术语从“不可变”更改为“不可修改”。然而,这里值得指出的是,术语的这种变化与新的“复制工厂方法”和新的收集器的添加有关,它们将使访问不可修改的集合变得更加容易。 JDK-8191517 总结了这些新方法:

  • “向copyOf()java.util.ListSet 添加一系列Map 方法以从中复制元素现有的集合或Map。”
  • “将收集器系列添加到 java.util.stream.Collectors,这将创建一个不可修改的 ListSetMap来自流。”

即将推出的 Map.copyOf(Map) 方法的 Javadoc 注释指出,“返回一个不可修改的 Map,其中包含给定 Map 的条目。给定的 Map 不能为 null,并且它不能包含任何 null 键或值。如果给定的 Map 随后被修改,则返回的 Map 将不会反映此类修改。” Javadoc 注释中的一个有趣(但并不奇怪)的“实施说明”指出,“如果给定的 Map 是不可修改的 Map ,则调用 copyOf 通常不会创建副本。”使用 Java 9 添加到 Map 的大量重载 Map.of() 方法修改了它们的 Javadoc 注释以将“immutable”替换为“unmodifiable”并替换对该部分的引用标题为“Immutable Map Static Factory Methods”,引用了该部分的新名称(“Unmodifiable Maps”)。术语“结构不可变”也被“不可修改”所取代。

Java 10 中的 Set.copyOf(Collection)List.copyOf(Collection) 方法与上一段中描述的 Map.copyOf(Map) 方法相似,并且在注释术语中包含相同的更改对于 Map

JDK-8191517 描述的 Java 10 中 Collectors 类的新增内容是四种方法 toUnmodifiableList()toUnmodifiableSet()$(一个版本接受一个 BinaryOperator 参数)。

随着不变性的优点得到更广泛的认识,并且随着 Java 开发人员努力在他们的应用程序中更频繁地应用不变性,准确地知道如何修改给定的结构、集合或视图通常很重要。 JDK 10 计划添加更多方法,使 Java 开发人员更容易实现集合的不变性(或至少不可修改性),最重要的接口和 Collections 类上的注释应该有助于开发人员更清楚地了解在他们为应用程序选择的结构中什么是可变的,什么是不可变的。

标签2: Java教程
地址:https://www.cundage.com/article/jcg-immutable-versus-unmodifiable-jdk-10.html

相关阅读

Java HashSet 教程展示了如何使用 Java HashSet 集合。 Java哈希集 HashSet 是一个不包含重复元素的集合。此类为基本操作(添加、删除、包含和大小)提供恒定时间性...
SpringApplicationBuilder 教程展示了如何使用 SpringApplicationBuilder 创建一个简单的 Spring Boot 应用程序。 春天 是用于创建企业应...
通道是继 buffers 之后 java.nio 的第二个主要新增内容,我们在之前的教程中已经详细了解了这一点。通道提供与 I/O 服务的直接连接。 通道是一种在字节缓冲区和通道另一端的实体(通...
课程大纲 Elasticsearch 是一个基于 Lucene 的搜索引擎。它提供了一个分布式的、支持多租户的全文搜索引擎,带有 HTTP Web 界面和无模式的 JSON 文档。 Elasti...
解析器是强大的工具,使用 ANTLR 可以编写可用于多种不同语言的各种解析器。 在这个完整的教程中,我们将: 解释基础:什么是解析器,它可以用来做什么 查看如何设置 ANTLR 以便在 Java...
Java 是用于开发各种桌面应用程序、Web 应用程序和移动应用程序的最流行的编程语言之一。以下文章将帮助您快速熟悉 Java 语言,并迈向 API 和云开发等更复杂的概念。 1. Java语言...
Java中的继承是指子类继承或获取父类的所有非私有属性和行为的能力。继承是面向对象编程的四大支柱之一,用于提高层次结构中类之间的代码可重用性。 在本教程中,我们将了解 Java 支持的继承类型,...
Java Message Service 是一种支持正式通信的 API,称为 网络上计算机之间的消息传递。 JMS 为支持 Java 程序的标准消息协议和消息服务提供了一个通用接口。 JMS 提...
之前,我介绍了spring 3 + hibernate 集成 示例和struts 2 hello world 示例。在本教程中,我将讨论在将 spring 框架与 struts 与 hibern...
Java 项目中的一项常见任务是将日期格式化或解析为字符串,反之亦然。解析日期意味着你有一个代表日期的字符串,例如“2017-08-3”,你想把它转换成一个代表 Java 中日期的对象,例如Ja...