Java:可选的可选实现

java.util.Optional被实现为单个不可变的具体类,该类在内部处理两种情况。 一个有元素,一个没有元素。 让Optional作为一个接口并让两个不同的实现代替实现是一个更好的选择吗? 毕竟,这就是我们通常被教导要使用的一种面向对象的语言。

在本文中,我们将了解当前Optional实现的一些潜在参数。 我们还将学习为什么以不同的方式实现Streams,从而使Streams可以从文件甚至数据库表中获取。

真正的可选实现

真正的java.util.Optional::get实现如下所示:

 public T get() { if (value == null ) { throw new NoSuchElementException( "No value present" ); } return value; } 

可以看出,有两个代码路径。 一种是值是null(没有元素,并且不会引发异常),另一种是值是其他值(返回值)。

可选可选实现

让我们假装我们将回到一台时光机,并被要求再次实现Optional 。 我认为我们中的许多人可能会提出一个初始解决方案,就像下面的解决方案(我将其命名为假设接口Option以便我们可以将其与“实际”接口分开)有两个截然不同的实现(此处为EmptyOptionPresentOption ):

 public interface Option<T> { T get(); boolean isPresent(); public <U> Option<U> map(Function<? super T, ? extends U> mapper); static <T> Option<T> empty() { return (Option<T>) EmptyOption.EMPTY; } (Option<T>) EmptyOption.EMPTY; } <T> Option<T> of(T value) { static <T> Option<T> of(T value) { return new PresentOption<>(value); } PresentOption<>(value); } <T> Option<T> ofNullable(T value) { static <T> Option<T> ofNullable(T value) { return value == null ? empty() : of(value); ? empty() : of(value); }  }  final class EmptyOption<T> implements Option<T> { static final EmptyOption<?> EMPTY = new EmptyOption<>(); private EmptyOption() {} @Override public T get() { throw new NoSuchElementException(); } NoSuchElementException(); } @Override public boolean isPresent() { return false ; } ; } @Override public <U> Option<U> map(Function<? super T, ? extends U> mapper) { requireNonNull(mapper); return (Option<U>) EMPTY; }  }  final class PresentOption<T> implements Option<T> { private final T value; PresentOption(T value) { this .value = requireNonNull(value); } .value = requireNonNull(value); } @Override public T get() { return value; } value; } @Override public boolean isPresent() { return true ; } ; } @Override public <U> Option<U> map(Function<? super T, ? extends U> mapper) { requireNonNull(mapper); return Option.ofNullable(mapper.apply(value)); }  } 

为了简洁起见,仅示出了几种方法,但是原理保持不变:针对存在元素和不存在元素的情况的不同实现。 这给出了更清晰的代码,也使任何人都可以实现可选选项。

分析

我有信心,在设想Optional时,JDK团队已对这种解决方案进行了评估,我认为这是明智的决定,不选择这种解决方案。 Optional主要目的是“包装”返回值,以防止NPE和返回原始空值的其他缺点。 我还认为设计目标是使用Optional对性能的影响应该很小或可以忽略不计。

在下文中,我推测了一些论点,以选择上述可选实现为基础的当前Optional实现。

剖面污染

JIT编译器按需编译Java字节码,以提高解释字节码的性能。

为了有效地做到这一点,JIT编译器能够收集每种已知方法的统计信息。 每个方法都可以具有一个MethodData对象,该对象包含有关如何使用该方法的度量,并且一旦JVM认为该方法足够“温暖”(即在某种意义上已被充分调用),便会创建该对象。

创建和维护MethodData过程称为“分析”。

当调用之间使用的方法大不相同时,就会发生“配置文件污染”,包括但不限于提供交替的非null / null元素并调用不同的多态方法(例如,参数是T类型的泛型,并且被调用的方法调用T::equals )。 Java的基本功能是其动态调用方法的能力。 因此,当调用Option::get时, EmptyOption::get
最终调用PresentOption::get取决于调用时存在的实现。

一旦该方法被调用了10,000次,JIT编译器就会使用MethodData创建一个有效的已编译代码段,根据迄今为止收集的统计信息,该代码段将以最佳方式执行。

因此,如果元素始终存在(使用PresentOption ),并且牢记这一点来编译代码,但随后突然出现EmptyOption ,则代码必须“退出”并采用慢得多的代码路径。

仅在最后一个类中使用Optional ,就不可能再有Optional方法的任何其他实现,因此,不会因不同的实现而造成配置文件污染。 JIT可以确定性且合理地快速确定编译的代码。

但是,等等,JVM不可能在启动时检查所有类并确定实际上只有两个实现类。
Option ,然后它可以解决整个问题? 好吧,不。 我们可以随时随意添加类,因此无法安全地枚举特定接口的所有可能实现。 至少要等到我们有了真正的Java密封类时,才能进行。

原料药污染

如果人们可以自由编写Optional自定义实现,那么与内置Optional相比,这些实现很可能会遭受设计缺陷/偏差。 同样,人们可能会让他们自己的类型实现Optional接口,这增加了JIT编译器/分析器的负担,并因此诱使人们使用非预期的复合类型(例如Foo implements Bar, Optional<Bazz>)

而且, Optional现在是Java不可或缺的一部分,因此,可以使它与JDK本身一起有效发展,包括内联类和其他即将推出的Java新功能。

可选与流

Optional相反, java.util.stream.Stream和专用版本(例如IntStream )确实是接口。 为什么Stream不像Optional那样具体地进行最后的上课?

好吧,Streams有一套完全不同的要求。 可以从Collection或数组中获取Stream但是有很多更强大的获取Stream 。 可以从文件,套接字,随机生成器甚至从数据库中的表获取Stream 。 如果Stream被密封,将无法实现这些功能。

Speedment Stream是一个库的示例,该库允许从几乎任何数据库中获取标准Java Streams。 在此处阅读有关Speedment Stream的更多信息。

结论

Optional密封,有充分的理由。 Optional的内部实现尚不明确,但这是值得付出的代价,它具有更好的性能和更清晰的用户代码。

流是非密封接口,任何人都可以实现,并可用于从各种来源(包括文件和数据库表)获取元素。 Speedment Stream ORM可用于从数据库表中获取Streams。

在此处下载Speedment Stream。

翻译自: https://www.javacodegeeks.com/2019/08/java-optional-implementation-optional.html

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

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

相关文章

mysql降低数据库版本_三步10分钟搞定数据库版本的降迁 (将后台数据库SQL2008R2降为SQ...

三步10分钟搞定数据库版本的降迁 (将SQL2008R2降为SQL2005版本) 前思后想仍觉得实战数据库版本的降迁一文中的方式不仅老土而且低效&#xff0c;故有了下文三步搞定数据库从MSSQL2008R2 高版本降迁至SQL2005低版本。 整个过程如果思路清晰&#xff0c;数据量小&#xff0c;不过…

2017菜鸡C与C++工程师总结,撸码撸码,垃圾专科生撸码人生

前言年底了&#xff0c;对工作做一个总结。又要感叹那句话啊&#xff0c;时光流水&#xff0c;仿佛昨天才刚毕业&#xff0c;到今天不知不觉已经正式工作半年了。文章以po主自己的心理想法和所见所闻入手来写&#xff0c;垃圾专科生&#xff0c;文笔不好勿怪。开始正文吧。关于…

primefaces_PrimeFaces 5.0 DataTable列切换器

primefaces我有机会与PrimeFaces 5.0 DataTable一起工作&#xff0c;并且增强功能很棒。 今天&#xff0c;我只想展示其中的一项新功能……DataTable列切换器。 通过此功能&#xff0c;可以通过复选框列表选择显示哪些列。 要使用列切换器&#xff0c;只需添加一个commandButt…

opencv 编译 python导入_openCV3 Python编译指南

这里主要对openCV官网的《Installation in Linux》文档进行了翻译和解释原文见&#xff1a;https://docs.opencv.org/3.4.1/doc/tutorials/introduction/linux_install/linux_install.html#linux-installationRequired Packages(需求包)GCC 4.4.x or laterCMake 2.6 or higherG…

Docker化Spring Boot应用程序

你好朋友&#xff0c; 在本教程中&#xff0c;我们将看到如何对Spring Boot应用程序进行Docker化。通过dockerizing意味着我们将以Docker容器的形式运行应用程序。 以下是涉及的步骤&#xff1a; 1.创建一个Spring Boot应用程序 2.在您的机器上安装Docker 3.在您的项目中创…

telephone 为空 唯一索引_PostgreSQL的空串、空值对唯一性约束的影响

一、现象及原因今天在PostgreSQL又遇到一个现象&#xff0c;应用代码报错&#xff1a;“ERROR: duplicate key value violates unique constraint ...”。最后查明&#xff0c;这是由于PostgreSQL把空串()、空值(NULL)当作不同的值&#xff0c;从而影响了那些没有申明为NOT NUL…

抱歉咯!今天偷个懒!!

今天偷个懒向大家推荐一个新建的C/C学习交流群。应为新建群人数不是很多&#xff0c;正在学习C/C或者正在寻求进阶的小伙伴都可以加下。作为群主会不时在群内分享学习资料的。

openshift_在WildFly和OpenShift上的WebSocket聊天

openshift聊天是解释WebSocket的最典型示例之一。 它是一个相当常用的界面&#xff0c;可以很容易地解释WebSocket的基本概念。 当然&#xff0c;Java EE 7 WebSocket也有一个&#xff0c; 在这里可用 &#xff01; 您可以使用以下步骤在WildFly上轻松运行它&#xff1a; curl…

linux 下脚本安装 mysql_linux(centos7)下编译安装mysql(数据库)一键安装详解+脚本文件...

一、下载源文件官网下载地址&#xff1a; https://downloads.mysql.com/archives/community/二、安装前准备(1)、开始之前先把虚拟机内存调大&#xff0c;避免安装时间过长和卡慢此处我调的内存为8个G(我的Windows内存为12G),如果你的电脑没有这么大运行内存可适度调小&#xf…

mysql数据库改成支持中文_修改Mysql编码支持中文

MySQL的默认编码是Latin1&#xff0c;不支持中文&#xff0c;要支持中午需要把数据库的默认编码修改为gbk或者utf8。1、需要以root用户身份登陆才可以查看数据库编码方式(以root用户身份登陆的命令为&#xff1a;>mysql -u root –p,之后两次输入root用户的密码)&#xff0c…

为什么学习C语言这么久,看的懂代码,做不出题,写不出来项目?

前言我看得懂别人的程序&#xff0c;可是我自己却写不出来&#xff0c;我应该怎么办啊&#xff1f;你了解这些嘛&#xff1f;你只是能从别人书写的代码知道每一步都做些什么吧&#xff1f;你明白别人的解题思路吗&#xff1f;你知道别人为什么要用那样的算法吗&#xff1f;如果…

如何在AWS中启动EC2实例

你好朋友&#xff0c; 在本教程中&#xff0c;我们将看到如何立即在AWS中旋转EC2实例。 您应该可以访问AWS控制台。如果您还没有AWS账户&#xff0c;则可以单击此处并在AWS上创建免费套餐。 如何在AWS中启动EC2实例 步骤1 &#xff1a; 使用您的凭证登录到您的AWS账户。 第…

git提交过滤package.json_eclipse配置git环境以及使用git提交本地仓和远程仓

一、Eclipse上安装GIT插件EGitEGit插件地址&#xff1a;http://download.eclipse.org/egit/updatesOK&#xff0c;随后连续下一步默认安装就可以&#xff0c;安装后进行重启Eclipse二、在Eclipse中配置EGitPreferences > Team > Git > Configuration注意这里的user.na…

dropbox_如何在Java中将图像上传到DropBox

dropbox本教程介绍了如何将图像上传到放置框并获取上传图像的公共URL。 首先&#xff0c;我们必须使用应用程序控制台创建一个DropBox API应用程序 。 创建应用程序后&#xff0c;您可以在应用程序属性中获取应用程序密钥和秘密密钥。 现在在pom文件中添加以下依赖项。 <…

C语言求一元二次方程的根,这题很简单嘛?看看这种想法很惊奇!

数学基础:一元二次方程只含有一个未知数&#xff08;一元&#xff09;&#xff0c;并且未知数项的最高次数是2&#xff08;二次&#xff09;的整式方程叫做一元二次方程。标准形式为&#xff1a;axbxc0&#xff08;a≠0&#xff09;。求解公式&#xff1a;求根公式法用求根公式…

新手学C语言会踩到什么样的坑?

C语言因为是很多计算机大学生的必修课&#xff0c;所以这门编程语言的小白很多&#xff0c;很多萌新都在学习的过程中流下了无数心酸的泪水。例如刚开始学习的“hello world”程序&#xff0c;这基本上是每个人踏入程序员的第一步&#xff0c;很多人的雄心壮志就是从这里开始的…

使用Spring Security进行简单身份验证

朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户&#xff1f; 立即尝试Okta的API和Java SDK。 在几分钟之内即可对任何应用程序中的用户进行身份验证&#xff0c;管理和保护。 身份验证对于除了最基本的Web应用程序之外的所有应用程序都至关重要。 谁在发出请求&#xf…

python程序、画一个笑脸_如何使用canvas画一个微笑的表情(代码示例)

本篇文章给大家带来的内容是关于如何使用canvas画一个微笑的表情(代码示例)&#xff0c;有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你有所帮助。实习期间让我用canvas画一个表情&#xff0c;比较简单&#xff0c;话不多说直接上代码&#xff1a;…

C语言项目:水波纹效果实现

今天教大家一个比较简单的C语言程序&#xff0c;通过用easyx库实现的水波纹效果。说到这里可能大家对水波纹似懂非懂&#xff0c;那么你肯定玩过这游戏吧&#xff01;编辑打水漂我们捡一块扁平的小石头或者瓦片&#xff0c;角度稍微倾斜的甩出去&#xff0c;在力的作用力下&…

jboss fuse 教程_在JBoss Fuse / Fabric8 / Karaf中使用Byteman

jboss fuse 教程您是否曾经尝试了解一些简单的东西不起作用的过程&#xff1f; 您正在任何众所周知的上下文中编写代码&#xff0c;无论出于何种原因它都无法正常工作。 而且您信任您的平台&#xff0c;因此您认真阅读了所有日志。 而且您仍然不知道为什么某些行为不符合预期…