java java se_Java 8 SE可选,严格的方法

java java se

大约两周前,Stephen Colebourne提出了使用Optional的实用方法 。 如果您阅读了它,您可能会从我以前的建议中猜到我不同意。

总览

我必须以免责声明开头,然后我将直接解释为什么我认为他的方法不那么理想。

所有不归因于他人的报价均摘自Stephen的帖子。 虽然并非绝对必要,但我建议先阅读它。 但是别忘了回来!

我创建了三个要点,这些要点在整个帖子中都会介绍: Stephen版本 , 基本版本和扩展版本中的相同示例。

免责声明

Stephen Colebourne是Java的传奇人物。 引用Markus Eisele的Java英雄关于他的文章:

Stephen Colebourne是OpenGamma的技术人员。 他以其在开源和博客中的工作而闻名。 他创建了Joda-Time,现在将其进一步开发为JSR-310 / ThreeTen。 他为关于Java未来的辩论做出了贡献,包括为泛型和FCM闭包的钻石运算符提出的建议,这两者都接近于Java 7和8中已采用的更改。Stephen是会议的常任发言人,JavaOne Rock Star和Java Champion。 。

我很高兴为斯蒂芬的房地产联盟做出贡献,这增强了我对他作为一个非常有能力的开发商和一个非常有思想的人的看法。

所有这些都表明,如果有疑问,请相信他。

事实是,他的方法根植于公理,即Optional应该仅用作返回类型。 这完全符合那些首先介绍该课程的人的建议。 引用Brian Goetz的话 :

当然,人们会做他们想要的。 但是,添加此功能时我们确实有明确的意图,并且它并不是通用的Maybe或Some类型,这是许多人希望我们这样做的原因。 我们的意图是为库方法返回类型提供一种有限的机制,其中需要一种明确的方式来表示“无结果”,而为此使用null则极有可能导致错误。

[…]几乎永远不要将其用作某些内容或方法参数的字段。

因此,如果有疑问,请相信他对我的看法。

由JD Hancock在CC-BY 2.0下发布。

发布时间由JD汉考克在CC-BY 2.0 。

并置

当然,比只相信任何人更好的是下定决心。 因此,与斯蒂芬的观点相反,这是我的观点。

基本要点

这些是斯蒂芬的五个基本要点:

  1. 不要声明任何类型为Optional的实例变量。
  2. 使用null表示类的私有范围内的可选数据。
  3. 对于访问可选字段的获取程序,请使用Optional。
  4. 不要在setter或构造方法中使用Optional。
  5. 对于具有可选结果的任何其他业务逻辑方法,请将Optional用作返回类型。

这是我的:

  1. 设计您的代码,以尽可能避免可选性。
  2. 在所有其他情况下,请选择Optional而不是null。

例子

让我们比较例子。 他的是:

Address.java,作者:Stephen Colebourne

public class Address {private final String addressLine;  // never nullprivate final String city;         // never nullprivate final String postcode;     // optional, thus may be null// constructor ensures non-null fields really are non-null// optional field can just be stored directly, as null means optionalpublic Address(String addressLine, String city, String postcode) {this.addressLine = Preconditions.chckNotNull(addressLine);this.city = Preconditions.chckNotNull(city);this.postcode = postcode;}// normal getterspublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// special getter for optional fieldpublic Optional<String> getPostcode() {return Optional.ofNullable(postcode);}// return optional instead of null for business logic methods that may not find a resultpublic static Optional<Address> findAddress(String userInput) {return... // find the address, returning Optional.empty() if not found}}

我喜欢此类的任何使用者都不能接收null。 我不喜欢您仍然需要如何处理-在课堂上还是在课堂上。

这将是我的(基本)版本:

我的Address.java(基本版)

public class Address {// look ma, no comments requiredprivate final String addressLine;private final String city;private final Optional<String> postcode;// nobody has to look at this constructor to check which parameters are// allowed to be null because of course none are!public Address(String addressLine, String city, Optional<String> postcode) {this.addressLine = requireNonNull(addressLine,"The argument 'addressLine' must not be null.");this.city = requireNonNull(city,"The argument 'city' must not be null.");this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}// of course methods that might not have a result// return 'Optional' instead of nullpublic static Optional<Address> findAddress(String userInput) {// find the address, returning Optional.empty() if not found}// getters are straight forward and can be generatedpublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// look how the field's type matches the getter's type;// nice for bean-based code/toolspublic Optional<String> getPostcode() {return postcode;}}

这里根本没有空值。

差异性

约束问题

在对象内,开发人员仍然被迫考虑null并使用!= null检查对其进行管理。 这是合理的,因为null问题受到了限制。 该代码将全部作为一个单元编写和测试(您确实编写测试不是吗?),因此null不会引起很多问题。

您看到他的构造函数如何允许其中一个参数为null吗? 找出哪一个需要您离开正在做的事情并查看其他类的代码的唯一方法。 这不是什么大事,但是没有必要。

即使撇开这一点,问题也没有受到应有的限制。 假设每个人都不喜欢注释 ,我们必须假定它们不存在,这使构造函数内部和getter的返回类型告诉您该字段可为空。 这不是让您跳出来的最佳信息。

很明显可选很明显

public class Address {// look ma, no comments requiredprivate final String addressLine;private final String city;private Optional<String> postcode;// nobody has to look at these constructors to check which parameters are// allowed to be null because of course none are!public Address(String addressLine, String city, Optional<String> postcode) {this.addressLine = requireNonNull(addressLine,"The argument 'addressLine' must not be null.");this.city = requireNonNull(city,"The argument 'city' must not be null.");this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public Address(String addressLine, String city, String postcode) {// use 'requireNonNull' inside Optional factory method// if you prefer a verbose exception message;// otherwise 'Optional.of(postcode)' sufficesthis(addressLine, city, Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null.")));}public Address(String addressLine, String city) {this(addressLine, city, Optional.empty());}// now if some method needs to use the postcode,// we can not overlook the fact that it is optionalpublic int comparePostcode(Address other) {// without Optionals we might overlook that the postcode// could be missing and do this:// return this.postcode.compareTo(other.postcode);if (this.postcode.isPresent() && other.postcode.isPresent())return this.postcode.get().compareTo(other.postcode.get());else if (this.postcode.isPresent())return 1;else if (other.postcode.isPresent())return -1;elsereturn 0;}// of course methods that might not have a result// return 'Optional' instead of nullpublic static Optional<Address> findAddress(String userInput) {// find the address, returning Optional.empty() if not found}// getters are straight forward and can be generatedpublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// look how the field's type matches the getter's type;// nice for bean-based code/toolspublic Optional<String> getPostcode() {return postcode;}// in case this 'Address' is mutable// (which it probably shouldn't be but let's presume it is)// you can decide whether you prefer a setter that takes an 'Optional',// a pair of methods to set an existing and an empty postcode, or bothpublic void setPostcode(Optional<String> postcode) {this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public void setPostcode(String postcode) {// again you might want to use 'requireNonNull'// if you prefer a verbose exception message;this.postcode = Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null."));}public void setEmptyPostcode() {this.postcode = Optional.empty();}}

他的测试论据可能会被数字打断。 如果所有测试都包含所有字段,则每个可选字段将使测试数量加倍,因为每个测试都应在null和non-null情况下运行。 我更喜欢将类型系统作为第一道防线。

另一方面,这种痛苦可能会说服开发人员在单个类中找到可选项较少的解决方案。

性能

Stephen正确指出,为方法返回值创建的实例然后被快速丢弃(这对于Optional的使用是典型的),几乎没有成本。 与Optional字段不同,后者在整个包含对象的整个生命周期中都存在,并增加了从该对象到Optional的有效负载的间接附加层。

对他来说,这是更喜欢null的原因。

虽然很容易断言这是“过早的优化”,但作为工程师,我们有责任了解我们所使用系统的限制和功能,并仔细选择应强调的点。

我同意。 但是对我来说,谨慎选择的一部分意味着要首先介绍。 而且,如果有人向我展示令人信服的论点,即在他的具体情况下,将某些Optional字段替换为可为空的字段会带来明显的性能提升,那么我会立即删除它们的愚蠢框。 但是在所有其他情况下,我坚持使用我认为更易于维护的代码。

顺便说一句,对于使用数组而不是ArrayLists或使用char-arrays而不是字符串,可以使用相同的参数。 我敢肯定,如果没有明显的性能提升,没有人会遵循该建议。

但是,讨论中的这个重复主题值得关注。 我将尝试寻找一些时间来介绍一些我认为很有趣的用例。

可序列化

尽管这只是次要点,但应注意,该类可以是可序列化的,如果任何字段为Optional(因为Optional不实现Serializable),则该类是不可能的。

我认为这是可以解决的 。 但是,这会导致一些额外的工作。

方便

我的经验是,在设置程序或构造函数上使用Optional对调用者很烦,因为它们通常具有实际对象。 强制调用者将参数包装在Optional中是一种麻烦,我希望不要对用户造成影响。 (即便利性胜过输入的严格性)

虽然编写令人讨厌的代码可能很有趣,但我明白了他的观点。 所以不要强迫用户,不要重载您的方法 :

重载构造函数以避免创建可选项

public class Address {// look ma, no comments requiredprivate final String addressLine;private final String city;private Optional<String> postcode;// nobody has to look at these constructors to check which parameters are// allowed to be null because of course none are!public Address(String addressLine, String city, Optional<String> postcode) {this.addressLine = requireNonNull(addressLine,"The argument 'addressLine' must not be null.");this.city = requireNonNull(city,"The argument 'city' must not be null.");this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public Address(String addressLine, String city, String postcode) {// use 'requireNonNull' inside Optional factory method// if you prefer a verbose exception message;// otherwise 'Optional.of(postcode)' sufficesthis(addressLine, city, Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null.")));}public Address(String addressLine, String city) {this(addressLine, city, Optional.empty());}// now if some method needs to use the postcode,// we can not overlook the fact that it is optionalpublic int comparePostcode(Address other) {// without Optionals we might overlook that the postcode// could be missing and do this:// return this.postcode.compareTo(other.postcode);if (this.postcode.isPresent() && other.postcode.isPresent())return this.postcode.get().compareTo(other.postcode.get());else if (this.postcode.isPresent())return 1;else if (other.postcode.isPresent())return -1;elsereturn 0;}// of course methods that might not have a result// return 'Optional' instead of nullpublic static Optional<Address> findAddress(String userInput) {// find the address, returning Optional.empty() if not found}// getters are straight forward and can be generatedpublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// look how the field's type matches the getter's type;// nice for bean-based code/toolspublic Optional<String> getPostcode() {return postcode;}// in case this 'Address' is mutable// (which it probably shouldn't be but let's presume it is)// you can decide whether you prefer a setter that takes an 'Optional',// a pair of methods to set an existing and an empty postcode, or bothpublic void setPostcode(Optional<String> postcode) {this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public void setPostcode(String postcode) {// again you might want to use 'requireNonNull'// if you prefer a verbose exception message;this.postcode = Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null."));}public void setEmptyPostcode() {this.postcode = Optional.empty();}}

当然,这在许多可选字段中无法很好地扩展。 在这种情况下,构建器模式会有所帮助。

事实是,如果我们的可为空的邮政编码中有一个setter,则处理其他代码的开发人员必须再次停止并查看此类,以确定她是否可以传递null。 由于她永远不能确定,因此她也必须检查其他吸气剂。 谈论烦人的代码...

使用Optional类型的字段,setter可能如下所示:

重载的二传手,避免创建可选项

public class Address {// look ma, no comments requiredprivate final String addressLine;private final String city;private Optional<String> postcode;// nobody has to look at these constructors to check which parameters are// allowed to be null because of course none are!public Address(String addressLine, String city, Optional<String> postcode) {this.addressLine = requireNonNull(addressLine,"The argument 'addressLine' must not be null.");this.city = requireNonNull(city,"The argument 'city' must not be null.");this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public Address(String addressLine, String city, String postcode) {// use 'requireNonNull' inside Optional factory method// if you prefer a verbose exception message;// otherwise 'Optional.of(postcode)' sufficesthis(addressLine, city, Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null.")));}public Address(String addressLine, String city) {this(addressLine, city, Optional.empty());}// now if some method needs to use the postcode,// we can not overlook the fact that it is optionalpublic int comparePostcode(Address other) {// without Optionals we might overlook that the postcode// could be missing and do this:// return this.postcode.compareTo(other.postcode);if (this.postcode.isPresent() && other.postcode.isPresent())return this.postcode.get().compareTo(other.postcode.get());else if (this.postcode.isPresent())return 1;else if (other.postcode.isPresent())return -1;elsereturn 0;}// of course methods that might not have a result// return 'Optional' instead of nullpublic static Optional<Address> findAddress(String userInput) {// find the address, returning Optional.empty() if not found}// getters are straight forward and can be generatedpublic String getAddressLine() {return addressLine;}public String getCity() {return city;}// look how the field's type matches the getter's type;// nice for bean-based code/toolspublic Optional<String> getPostcode() {return postcode;}// in case this 'Address' is mutable// (which it probably shouldn't be but let's presume it is)// you can decide whether you prefer a setter that takes an 'Optional',// a pair of methods to set an existing and an empty postcode, or bothpublic void setPostcode(Optional<String> postcode) {this.postcode = requireNonNull(postcode,"The argument 'postcode' must not be null.");}public void setPostcode(String postcode) {// again you might want to use 'requireNonNull'// if you prefer a verbose exception message;this.postcode = Optional.of(requireNonNull(postcode,"The argument 'postcode' must not be null."));}public void setEmptyPostcode() {this.postcode = Optional.empty();}}

同样,所有的空值都会立即得到答复,但有例外。

豆子

不利的一面是,这种方法导致的对象不是bean。

是的 拥有类型为Optional的字段不会因此受到影响。

共性

我们在这里讨论细节不容忽视。 我们的目标是相同的,并且我们提出了类似的实现目标的方法。

如果在应用程序中广泛采用,则null问题趋于消失而无需付出很大的努力。 由于每个域对象都拒绝返回null,因此应用程序往往永远不会传递null。 以我的经验,采用这种方法往往会导致在类的私有范围之外从未使用过null的代码。 重要的是,这自然而然地发生了,而不是一个痛苦的过渡。 随着时间的流逝,您开始编写防御性较小的代码,因为您更有信心没有任何变量实际包含null。

这是一个伟大的目标! 并遵循斯蒂芬的建议将带给您大部分帮助。 因此,不要以我的不同为理由而不使用Optional。

我要说的是,我几乎没有理由停止更多地禁止null!

反射

每当有可为空的内容时,我就解决一些问题并希望驳斥一些反对使用Optional的论点。 我希望表明我更严格的方法在驱散null方面做得更好。 这应该使您有更多的精力去思考更多相关的问题。

付出的代价可能会降低性能。 如果有人证明更多,对于这些特定情况,我们仍然可以返回null。 或将硬件扔在问题上。 或等待值类型 。

你怎么看?

翻译自: https://www.javacodegeeks.com/2015/08/java-8-se-optional-a-strict-approach.html

java java se

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

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

相关文章

std::thread 还有哪些使用“姿势”?

点击蓝字关注我们C11 线程创建每一个 C11 程序都包含一个主线程即 main() 函数。在 C11 中我们可以通过创建 std::thread 对象来创建新的线程。每个 std::thread 对象都可以与一个线程相关联。需要引用的头文件&#xff1a;1#include <thread>std::thread 的构造函数中接…

用python画皇冠_手把手教你用 Python 绘制酷炫的桑基图!

原标题&#xff1a;手把手教你用 Python 绘制酷炫的桑基图&#xff01;作者 | 周志鹏 责编 | 郭 芮 最近&#xff0c;不止一次收到小伙伴的截图追问&#xff1a;“这个图叫什么&#xff1f;&#xff1f;&#xff1f;” “这个图真好看&#xff01;&#xff01;&#xff01;怎么…

为啥电脑从C盘开始?A、B盘去哪了?

点击蓝字关注我们前些天硬盘坏了&#xff0c;幸好不是系统盘&#xff0c;不然那些软件安装配置会把我折腾坏&#xff0c;或许这也是在暗示我该换电脑了。重要的数据部分没有遭到损坏&#xff0c;数据是无价的&#xff0c;还是要勤备份。于是换上了一张新的硬盘&#xff0c;当时…

java 锁_Java之线程并发的各种锁、锁、锁

因为两周没更新了...也不是懒&#xff0c;这两周确实有些忙&#xff0c;赶项目进度赶的不亦乐乎...终于赶在工期前&#xff0c;可以进入内测了&#xff0c;我也有了些时间&#xff0c;可以更新啦...线程并发锁是很常见的问题&#xff0c;而且在Java中锁的类型、概念、使用场景等…

C语言编程中错误异常该如何统一处理?1.8万字总结

点击蓝字关注我们本文主要总结嵌入式系统C语言编程中&#xff0c;主要的错误处理方式。一、错误概念1.1 错误分类从严重性而言&#xff0c;程序错误可分为致命性和非致命性两类。对于致命性错误&#xff0c;无法执行恢复动作&#xff0c;最多只能在用户屏幕上打印出错消息或将其…

pycharm remote 远程项目 同步 本地_利器:PyCharm本地连接服务器搭建深度学习实验环境的三重境界...

作为实验室社畜&#xff0c;常需要在本地使用Pycharm写代码&#xff0c;然后将代码同步到服务器上&#xff0c;使用远程登录服务器并运行代码做实验。这其中有很多事情如果没有好的工具&#xff0c;做起来会非常麻烦。比如如何快速同步本地与服务器的代码&#xff1f;如何优雅地…

防御性编程技巧

点击蓝字关注我们在防御性编程的大框架之下&#xff0c;有许多常识性的规则。人们在想到防御性编程的时候&#xff0c;通常都会想到“断言”&#xff0c;这没有错。我们将在后面对此进行讨论。但是&#xff0c;还是有一些简单的编程习惯可以极大地提高代码的安全性。尽管看上去…

cookie无法读取bdstoken_第二章(第12节):cookie操作

有时候我们需要验证浏览器中 cookie 是否正确&#xff0c;因为基于真实 cookie 的测试是无法通过白盒和集成测试进行的。WebDriver 提供了操作 cookie 的相关方法&#xff0c;可以读取、添加和删除 cookie信息。WebDriver 操作 cookie 的方法&#xff1a;get_cookies()&#xf…

C++ 基本的输入输出

点击蓝字关注我们C 标准库虽然提供了一组丰富的输入/输出功能&#xff0c;但是本章只讨论 C 编程中最基本和最常见的 I/O 操作。C 的 I/O 发生在流中&#xff0c;流是字节序列。如果字节流是从设备&#xff08;如键盘、磁盘驱动器、网络连接等&#xff09;流向内存&#xff0c;…

http 和 https_HTTPS与HTTP区别

HTTPS与HTTP的认识&#xff1a;HTTP 加密 认证 完整性保护 HTTPSHTTP的全称是 Hypertext Transfer Protocol Vertion (超文本传输协议)HTTPS&#xff1a; HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议。HTTPS和HTTP的区别&#xff1a;HTTPS协议需要到ca申…

C语言指针的自我介绍(你了解我吗?了解多少?)

点击蓝字关注我们hey! Ladies and Gentlemen.&#x1f601;欢迎大家来看望我&#xff0c;对&#xff0c;我就是指针(pointer)&#xff0c;被很多人吐槽&#x1f614;&#xff0c;也被人说好。我希望大家了解过我以后&#xff0c;能够爱上我&#x1f618;。大家在了解我之前 &am…

flex 解析json文件_使用 Python 处理 JSON 格式的数据 | Linux 中国

如果你不希望从头开始创造一种数据格式来存放数据&#xff0c;JSON 是一个很好的选择。如果你对 Python 有所了解&#xff0c;就更加事半功倍了。下面就来介绍一下如何使用 Python 处理 JSON 数据。-- Seth KenlonJSON 的全称是 JavaScript 对象表示法JavaScript Object Notati…

【C语言】指针进阶第一站:字符指针 typedef关键字!

点击蓝字关注我们简单回顾一下指针的概念内存会划分以字节为单位的空间&#xff0c;每一个字节都有一个编号&#xff08;地址/指针&#xff09;指针变量可以存放这个地址/指针注&#xff1a;我们日常所说的指针&#xff0c;一般是指针变量下面让我们坐上指针进阶的直通车&#…

python编译helloworld_python3学习笔记--001--python HelloWorld

python默认使用UTF-8编码 一个python3版本的HelloWorld代码如下&#xff1a; #!/usr/bin/env python print (Hello World!) 如果此python脚本文件名为&#xff1a;hello.py&#xff0c;则运行此脚本文件的方法有两种&#xff1a; 1、python hello.py [laolanglocalhost python]…

漫谈 C++:良好的编程习惯与编程要点

点击蓝字关注我们以良好的方式编写C class假设现在我们要实现一个复数类complex&#xff0c;在类的实现过程中探索良好的编程习惯。① Header(头文件)中的防卫式声明complex.h: # ifndef __COMPLEX__ # define __COMPLEX__ class complex {} # endif防止头文件的内容被多次包含…

【C语言】指针进阶第二站:指针数组!

点击蓝字关注我们指针数组数组是一种类型的数的集合整型数组的元素都是int类型指针数组的元素都是指针变量int* arr1[10];//整型指针的数组char*arr2[10];//一级字符指针的数组char** arr3[5];//二级字符指针的数组参考这一份示意图示例1:定义多个字符指针在上一站的字符指针里…

C语言初学者常见错误 | 总结22点

点击蓝字关注我们正文一.语言使用错误在打代码的过程中&#xff0c;经常需要在中文与英文中进行转换&#xff0c;因此常出现一些符号一不小心就用错&#xff0c;用成中文。例如&#xff1a;“&#xff1b;”中文中的分号占用了两个字节&#xff0c;而英文中“;”分号只占用一个…

nginx配置vue项目500_一个Nginx部署多个vue前端项目总结

摘要&#xff1a;近来接手了一个二次开发的前后端分离模式的项目&#xff0c;其中在前端项目的部署上需要让2个前端项目都部署到一个IP地址和端口下&#xff0c;那么我们这里就要用到Nginx了&#xff0c;接下来我们看看如何在一个Nginx下部署2个前端项目的编译打包2个前端项目执…

【C语言】指针进阶第三站,数组指针!

点击蓝字关注我们数组指针整型指针&#xff1a;指向整型的指针字符指针&#xff1a;指向字符的指针数组指针&#xff1a;指向数组的指针基本概念下面哪个是数组指针呢&#xff1f;指针数组和数组指针的概念很容易混淆&#xff0c;一定要分清楚哦&#xff01;int *p1[10]; int (…

【C语言】指针进阶第四站:数组/指针的传参问题!

点击蓝字关注我们朋友们&#xff0c;到站啦&#xff01;指针进阶第四站&#xff1a;传参问题0.引例自定义函数里形参的类型&#xff0c;要和函数调用中传过去的实参类型相对应test函数里的是int类型&#xff0c;我们传过去的参数a也是int类型void test(int n) {} int main() {i…