Java 8 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. 对于访问可选字段的吸气剂,请使用可选。
  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();}}

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

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

性能

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

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

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

相关文章

routersploit简单实例

https://github.com/reverse-shell/routersploit RouterSploit。它包含了27个品牌的上百种漏洞利用模块&#xff0c;涉及的路由器、摄像头等设备有几百种。渗透的时候&#xff0c;用户首先根据目标设备的品牌选择对应的扫描模块&#xff0c;用以发现漏洞。一旦漏洞识别&#x…

《Spring3.0就这么简单》

第一章 认识Spring 1、Spring提供的IOC容器&#xff0c;是Spring大杀器之一。容器将对象之间的依赖关系交给Spring进行控制&#xff0c;采用配制的方式对依赖关系进行描述&#xff0c;由Ioc容器负责依赖类之间的创建、拼接、管理、获取工作 2、Spring提供的第二大杀器&#xff…

前端面试题之http/HTML/浏览器(一)

1.cookie sessionStorage localStorage区别&#xff1f;答&#xff1a;cookie数据始终在同源的http请求中携带(即使不需要)&#xff0c;即cookie在浏览器和服务器间来回传递cookie数据还有路径&#xff08;path&#xff09;的概念&#xff0c;可以限制。cookie只属于某个路径下…

[Vulhub](WooYun-2016-199433)phpmyadmin反序列化漏洞

0x00 预备知识 什么是序列化 序列化 (serialize)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间&#xff0c;对象将其当前状态写入到临时或持久性存储区。以后&#xff0c;可以通过从存储区中读取或反序列化对象的状态&#xff0c;重新创建该对象。【将状…

用户指南接口

在AppDelegate在代码 视图控制器里的 版权声明&#xff1a;本文博客原创文章。博客&#xff0c;未经同意&#xff0c;不得转载。 转载于:https://www.cnblogs.com/bhlsheji/p/4747547.html

前端面试题之http/HTML/浏览器(二)

csrf和xss的网络攻击及防范&#xff1f;答&#xff1a;CSRF&#xff1a;跨站请求伪造&#xff0c;可以理解为攻击者盗用了用户的身份&#xff0c;以用户的名义发送了恶意请求&#xff0c;比如用户登录了一个网站后&#xff0c;立刻在另一个&#xff54;&#xff41;&#xff42…

查看目标主机安装的杀毒软件

命令&#xff1a; wmic /namespace:\\root\securitycenter2 path antivirusproduct GET displayName,productState, pathToSignedProductExe 参考链接&#xff1a;https://stackoverflow.com/questions/42472336/is-there-a-command-to-check-if-there-was-any-antivirus-insta…

Netty系列之Netty百万级推送服务设计要点

原文&#xff1a;http://www.infoq.com/cn/articles/netty-million-level-push-service-design-points 1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我&#xff0c;咨询推送服务相关的问题。问题五花八门&#xff0c;在帮助大家答疑…

上架APPStore需要准备哪些材料?

前端时间用敏捷式开发平台开发了一款APP应用&#xff0c;应用名称我就不说啦&#xff0c;这篇文章主要讲述一下上架苹果应用商店APPStore需要准备哪些材料&#xff0c;有相关的困扰欢迎私信我。一、上架流程1. 注册苹果企业账号2. 创建测试证书&#xff0c;发布证书 (使用Mac)3…

浅谈C++设计模式之工厂方法(Factory Method)

为什么要用设计模式&#xff1f;根本原因是为了代码复用&#xff0c;增加可维护性。 面向对象设计坚持的原则&#xff1a;开闭原则&#xff08;Open Closed Principle&#xff0c;OCP&#xff09;、里氏代换原则&#xff08;Liskov Substitution Principle&#xff0c;LSP&…

上架Android应用到腾讯应用包、百度手机助手、华为应用市场、小米应用商店、阿里应用分发平台需要准备哪些材料?...

前端时间用敏捷式开发平台开发了一款APP应用&#xff0c;应用名称我就不说啦&#xff0c;这篇文章主要讲述一下上架各大安卓应用商店&#xff08;腾讯应用宝、阿里应用商店、百度手机助手、华为应用市场、小米应用商店&#xff09;需要准备哪些材料&#xff0c;有相关的困扰欢迎…

【APICloud系列|18】上架Android应用到腾讯应用包、百度手机助手、华为应用市场、小米应用商店、阿里应用分发平台需要准备哪些材料?

前端时间用敏捷式开发平台开发了一款APP应用,应用名称我就不说啦,这篇文章主要讲述一下上架各大安卓应用商店(腾讯应用宝、阿里应用商店、百度手机助手、华为应用市场、小米应用商店)需要准备哪些材料,有相关的困扰欢迎私信我。 一、应用商店选择 推荐平台(六选五) 1.…

Activiti 6中的可插拔持久性

在过去的几年中&#xff0c;我们经常听到&#xff08;来自社区和我们的客户&#xff09;关于如何将Activiti的持久性逻辑从关系数据库交换到其他内容的请求。 当我们宣布Activiti 6时&#xff0c; 我们做出的承诺之一就是我们将实现这一目标。 深入研究Activiti引擎代码的人会…

src漏洞类型总结

本文转载于https://blog.csdn.net/qq_33942040/article/details/111831536 这三类存在漏洞可能更大 越他娘丑的站&#xff0c;越有可能存在洞。 Asp aspx 存在漏洞的可能更大 登陆口没得验证码的可能存在一,未授权访问 常见28种服务器或者中间协议未授权访问 易出现处 ①照片…

【APICloud系列|19】上架APPStore需要准备哪些材料?

前端时间用敏捷式开发平台开发了一款APP应用,应用名称我就不说啦,这篇文章主要讲述一下上架苹果应用商店APPStore需要准备哪些材料,有相关的困扰欢迎私信我。 一、上架流程 1. 注册苹果企业账号 2. 创建测试证书,发布证书 (使用Mac) 3. 使用xcode 上传应用到APP Store (…

Json注入

一、Json简介 JSON 是存储和交换文本信息的语法&#xff0c;是轻量级的文本数据交换格式。类似xml&#xff0c;但JSON 比 XML 更小、更快&#xff0c;更易解析。所以现在接口数据传输都采用json方式进行。JSON 文本的 MIME 类型是 “application/json”。 json语法 数据在名…

国行 lg g3 D858 刷 lg g3 D858hk 教程(备忘)

纯手打&#xff0c;转载请注明出处~ 刷机有风险&#xff0c;出现问题概不负责&#xff01; 本着自娱自乐的宗旨 &#xff0c;分享一下&#xff0c;出了问题不负责&#xff01; 准备的材料&#xff1a; 1&#xff0c;手机一枚&#xff08;废话&#xff09;国行lg g3 d858 2&am…

渗透测试-验证码的爆破与绕过

【验证码机制原理】 客户端发起请求->服务端响应并创建一个新的SessionID同时生成随机验证码&#xff0c;将验证码和SessionID一并返回给客户端->客户端提交验证码连同SessionID给服务端->服务端验证验证码同时销毁当前会话&#xff0c;返回给客户端结果。 【客户端可…

最近对项目代码做的一些更改和感想

最近对项目代码做了一些更改&#xff0c;主要的改动是对整个界面框架的改变&#xff0c;因为以前写代码的时候&#xff0c;为了完成功能&#xff0c;没有从上帝视角来思考软件的界面设计&#xff0c;完全是需要这个功能了&#xff0c;怎么可以做到&#xff1f;好&#xff0c;就…

CSS常见的四种垂直居中的方法

面试中不管是笔试题还是面试题,一般很容易被问到如何实现垂直水平居中,这里总结四种方法作为参考 (1)margin:auto法 css: div{ width: 400px; height: 400px; position: relative; border: 1px solid #465468; } img{ position: absolute; margin: auto; top: 0; left: 0; …