为什么要使用Optional
Why use Optional? NullPointerException
有个很有名的说法: Null Pointer References: The Billion Dollar Mistake,这是发明null指针的人提出来的。(https://medium.com/@hinchman_amanda/null-pointer-references-the-billion-dollar-mistake-1e616534d485)
为什么说空指针是十亿美元的错误,其实不光是java,在其他编程语言中,也经常会遇到空指针异常的问题。可以说这是一个编程中出现最频繁的bug,有人说70%以上的异常都是NullPointerException。我们可以看下代码:
String str=new String("hello world");
str.trim();
如果我们只是写个简单的Demo,new一个简单对象,然后调用,当然ok, 不会有任何问题。但是一旦到了真实项目中,就会有很多问题,因为实际编程环境往往复杂得多,代码如下:
String str=getMsgFormDB();
str=str.trim();
// 或者
str=str.replace(getMsgFromWebService());
str=str.trim();
- 问题在哪里,哪一步会抛异常,抛出什么异常(不考虑调用方法抛出异常的情况)?
通常会在str.trim()或str.append()这一步出现NullPointerException,因为str可能会是一个null值,而调用null对象的方法就是空指针异常了。
那么我们一般是怎么那避免这个问题?如果有过一些实战经验的,不管用什么语言开发我们多少都会在踩坑培养出谨慎态度,哪就是不相信任何被调用的代码(包括自己写的方法),比如上面代码我们会这样写:
String str=getMsgFormDB();
if(null != str){
str.trim();
str=str.replace(getMsgFromWebService());
}
if(null != str){
str= str.trim();
}
这样写,就保证了程序的健壮性,杜绝了NullPointerException。但是这就带来了一个问题,代码变得非常啰嗦,不可读性,想想看如果我们写一个比较复杂的业务,我们会写一堆非空检查,而且会层层嵌套,如:
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String isocode = country.getIsocode();
if (isocode != null) {
isocode = isocode.toUpperCase();
}
}
}
}
那么有没有办法即保证程序健壮性的同时,又保持代码的优雅和可读性,Optional就是在java 8中提出的解决方案,看如下代码:
String str= Optional.ofNullable(getMsgFormDB()) //1
.map(d->d.trim()) //2
.map(d->d.replace(getMsgFromWebService())) //3
.map(d->d.trim()) //4
.orElseGet(() -> Strings.EMPTY); //5
上面的这一行代码实际上是一个连续的调用链,使用了lambda表达式和Optional多个函数,我们可以把它如下拆开来分析,代码如下:
String str;
//1. 这是用Optional包装了String的可空对象
Optional<String> strOpt= Optional.ofNullable(getMsgFormDB());
//2. map函数是将Optional包装的对象转换成其他对象,可以是其他类型对象,这里只是将String转换成不同值String对象,并且map函数是有一个隐含逻辑的,就是只有Optional里面第二次String 不为null时才执行你传入map中的Lambda表达式。
strOpt= strOpt.map(d->d.trim());
//3 ...
strOpt= strOpt.map(d->d.replace(getMsgFromWebService()))
//4 ...
strOpt= strOpt.map(d->d.trim())
//5 orElseGet函数的意思是,如果strOpt中String对象为null,则执行传入其中的表达式,这一行是返回了一个空字符串。Optional还有一个类似的orElse(),它和orElseGet区别是,它返回一个Optional包装类型对象
strOpt= strOpt.orElseGet(() -> Strings.EMPTY);
上面的代码和上上面的代码,其整个组成的逻辑就是,用Optional包装从调用getMsgFormDB()方法返回的对象,如果getMsgFormDB()返回的对象不为null,将其转换成一个去除空格的String对象,并一次执行第三不,第四步的转换。 如果getMsgFormDB()返回的对象为null,则不执行2,3,4这几个传入map函数中的表达式,我们且当做未执行2,3,4这三行代码,直接执行了第5行代码。
以上示例展示了如何使用Optional类来组装我们的代码,它可以使我们的代码变成一个链式的,易于阅读的,且一定曾读增强了代码的健壮性。Optional类还有许多其他函数来做一些我们需要的常规操作,如: isPresent(),isPresent(),isPresent(),ifPresent等等,可参考如下教程: https://www.runoob.com/java/java8-optional-class.html
另外有一个实践建议,我不是很清楚它是否完全正确,我们可以权衡一下。
- 我们应该尽量避免在代码中范型型参,方法入参或返回类型类型中使用Optional,如:
// 可以这样用
public void youMethod(){
Any str=Optional.ofNullable(getObjectByOthers()).orElseGet(()-> new Any());
//... doSomething
}
// 不要这样做
public Optional<Any> youMehtod(Optional<Any> arg){
}
为什么要使用Optional的更多相关文章
- [翻译]理解Swift中的Optional
原文出处:Understanding Optionals in Swift 苹果新的Swift编程语言带来了一些新的技巧,能使软件开发比以往更方便.更安全.然而,一个很有力的特性Optional,在你 ...
- Atitit. null错误的设计 使用Optional来处理null
Atitit. null错误的设计 使用Optional来处理null 然后,我们再看看null还会引入什么问题. 看看下面这个代码: String address = person.getCount ...
- Guava学习笔记(1):Optional优雅的使用null
转自:http://www.cnblogs.com/peida/archive/2013/06/14/Guava_Optional.html 参考:[Google Guava] 1.1-使用和避免nu ...
- guava – Optional
过多的使用null可能会导致大量的bugs,Google code 底层代码中,95%的集合类默认不接受null值.对null值,使用快速失败拒绝null比默认接受更好. 另外,null本身的含义很模 ...
- JAVA 8 Optional类介绍及其源码
什么是Optional对象 Java 8中所谓的Optional对象,即一个容器对象,该对象可以包含一个null或非null值.如果该值不为null,则调用isPresent()方法将返回true,且 ...
- maven可选依赖(Optional Dependencies)和依赖排除(Dependency Exclusions)
我们知道,maven的依赖关系是有传递性的.如:A-->B,B-->C.但有时候,项目A可能不是必需依赖C,因此需要在项目A中排除对A的依赖.在maven的依赖管理中,有两种方式可以对依赖 ...
- Java 8 Optional类深度解析
身为一名Java程序员,大家可能都有这样的经历:调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法.我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数. ...
- Swift中的Optional类型 (可选类型)与强制解包 ? !
我们在swift的开发中会经常遇见?和! ,理解这两个符号深层次的内容对我们的开发是相当有利的: 目前网上对swift3.0的教程还相当的少,如果去搜索会发现早期的说法,在定义变量的时候,swift是 ...
- Swift开发第五篇——四个知识点(Struct Mutable方法&Tuple&autoclosure&Optional Chain)
本篇分三部分: 一.Struct Mutable方法 二.多元组(Tuple) 的使用 三.autoclosure 的使用 四.Optional Chain 的使用 一.Struct Mutable方 ...
- initializer for conditional binding must have optional type not AVAudioPlayer
if let buttonBeep = self.setupAudioPlayerWithFile("ButtonTap", type: "wav") { ...
随机推荐
- 【转】自动化框架中引入ExtentReport美化报告
本文链接:https://blog.csdn.net/qq_30353203/article/details/82023922一.先引入三个依赖包 <dependency> <gro ...
- K8S集群Master高可用实践
K8S集群Master高可用实践 https://blog.51cto.com/ylw6006/2164981 本文将在前文基础上介绍k8s集群的高可用实践,一般来讲,k8s集群高可用主要包含以 ...
- Nexus3.X忘记admin密码找回
一.问题背景 nexus3 这种东西,传完一次,很少动了,很容易忘记密码,不要急有方法找回. 官方网站关于解决该问题的方法: https://support.sonatype.com/hc/en-us ...
- idea 报错javax/xml/bind/DatatypeConverter
idea 报错javax/xml/bind/DatatypeConverter java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeCon ...
- 异常检测-基于孤立森林算法Isolation-based Anomaly Detection-3-例子
参考:https://scikit-learn.org/stable/auto_examples/ensemble/plot_isolation_forest.html#sphx-glr-auto-e ...
- windows下新增项目本地通过git bash推送至远程github
本地E盘workspace目录下新增了spring-cloud-alibaba-demo项目,还没有编译过,没有target等不需要推送至git的文件,所以就直接用git bash丢到github了. ...
- 使用java移位运算符进行转化
import java.util.Scanner; public class Main { public static void main(String[] args) { new Main().sy ...
- Hadoop记录-HDFS均衡脚本
#!/bin/bash #作用:hdfs使用率取最大100个主机和最小80个主机进行数据均衡 #打印报告 hdfs dfsadmin -report>report.txt #截取主机名 cat ...
- Django自定义用户认证系统之自定义用户模型
参考文档:http://python.usyiyi.cn/django/topics/auth/customizing.html Django 自带的认证系统足够应付大多数情况,但你或许不打算使用现成 ...
- Speech Recognition Java Code - HMM VQ MFCC ( Hidden markov model, Vector Quantization and Mel Filter Cepstral Coefficient)
Hi everyone,I have shared speech recognition code inhttps://github.com/gtiwari333/speech-recognition ...