如何更好地使用Java 8的Optional
Java 8中的Optional<T>
是一个可以包含或不可以包含非空值的容器对象,在 Stream API中很多地方也都使用到了Optional。
java中非常讨厌的一点就是nullpoint,碰到空指针就会出错抛Exception,然后需要逐行检查是哪个对象为空,带来大量的不必要精力损耗,抛出NPE错误不是用户操作的错误,而是开发人员的错误,应该被避免,那么只能在每个方法中加入非空检查,阅读性和维护性都比较差。
如下面这个代码的手工非空检查:
public
void
addAddressToCustomer(Customer customer, Address newAddress){
if
( customer ==
null
|| newAddress ==
null
)
return
;
if
( customer.getAddresses() ==
null
){
customer.setAddresses (
new
ArrayList<>());
}
customer.addAddress(newAddress);
}
另外还有一些开发人员喜欢通过非空检查来实现业务逻辑,空对象不应该用来决定系统的行为,它们是意外的Exceptional值,应当被看成是错误,而不是业务逻辑状态。
当我们一个方法返回List集合时,应该总是返回一个空的List,而不是Null,这就允许调用者能够遍历它而不必检查Null,否则就抛出NPE。
但是如果我们根据标识键ID查询数据库,没有查到,需要返回一个空对象怎么办?有人建议抛出Exception,其实这不符合函数方法一进一出的原则,变成一个函数方法有两个返回,一个是正常返回,一个出错Exception,函数式编程范式告诫我们不要轻易抛Exception。
这时Java 8的Optional就发挥作用了,允许我们返回一个空的对象。
Optional<T>有方法 isPresent() 和 get() 是用来检查其包含的对象是否为空或不是,然后返回它,如:
Optional<SomeType> someValue = someMethod();
if (someValue.isPresent()) { // check
someValue.get().someOtherMethod(); // retrieve and call
}
但是这种用法并不能体现Java 8的全部好处,你可以将Optional看成是需要使用某个T值的方法之间某种中间人或者协调者Mediator,而不只是一个普通对象的包装器。
如果你有一个值返回类型T,你有一个方法需要使用这个值,那么你可以让 Optional<T> 处于中间,确保它们之间交互进行,而不必要人工干预。
这样,协调者Optional<T>能够照顾T的值提供给你的方法作为输入参数,在这种情况下,如果T是空,可以确保不会出错,这样在T值为空时也可以让一切都正常运作,你也可以让Optional<T>执行其他动作,如执行一段代码块等等,这样它就实际上是语言机制的很好的补充。
下面这个案例涉及到Lambda表达式 方法引用,是将单词流中第一个以"L"开始单词取出,作为返回结果是一个Optional<String>。
使用ifPresent()
这个案例的代码如下:
Stream<string> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");
Optional<string> longest = names
.filter(name -> name.startsWith("L"))
.findFirst();
longest.ifPresent(name -> {
String s = name.toUpperCase();
System.out.println("The longest name is "+ s);
});
这里ifPresent() 是将一个Lambda表达式作为输入,T值如果不为空将传入这个lambda。那么这个lambda将不为空的单词转为大写输出显示。在前面names单词流寻找结果中,有可能找不到开始字母为L的单词,返回为空,也可能找到不为空,这两种情况都传入lambda中,无需我们打开盒子自己编写代码来判断,它自动帮助我们完成了,无需人工干预。
使用map()
如果你想从Optional<T>中返回一个值怎么办?使用 map(),如下:
Stream<string> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");
Optional<string> longest = names
.filter(name -> name.startsWith("L"))
.findFirst();
Optional<string> lNameInCaps = longest.map(String::toUpperCase);
使用Optional<T>的map方法能够返回另外一个Optional,如上面的 LnameInCaps,因为传入map()的参数值也许会导致一个空值。
使用orElse()
如果在T可能空时你需要一个值的话,那么可以使用orElse(),它能在T值存在的情况下返回这个值,否则返回输入值。
Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");
Optional<String> longest = names
.filter(name -> name.startsWith("Q"))
.findFirst();
String alternate = longest.orElse("Nimrod");
System.out.println(alternate); //prints out "Nimrod"
使用orElseGet()
orElseGet() 方法类似于orElse(),但是不是直接返回输入参数,而是调用输入参数,返回调用的结果,这个输入参数通常是lambda:
Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");
Optional<String> longest = names
.filter(name -> name.startsWith("Q"))
.findFirst();
String alternate = longest.orElseGet(() -> {
// perform some interesting code operation
// then return the alternate value.
return "Nimrod";
});
System.out.println(alternate);
使用 orElseThrow()
orElseThrow()是在当遭遇Null时,决定抛出哪个Exception时使用:
Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");
Optional<String> longest = names
.filter(name -> name.startsWith("Q"))
.findFirst();
longest.orElseThrow(NoSuchElementStartingWithQException::new);
总结,你能创建下面三种类型的Optional<T>:
Optional<SomeType> getSomeValue() {
// 返回一个空的Optional类型;
return Optional.empty();
}
Optional<SomeType> getSomeValue() {
SomeType value = ...;
// 使用这个方法,值不可以为空,否则抛exception
return Optional.of(value);
}
Optional<SomeType> getSomeValue() {
SomeType value = ...;
// 使用这个方法,值可以为空,如果为空返回Optional.empty
return Optional.ofNullable(value);
// usage
Optional<SomeType> someType = getSomeValue();
如何更好地使用Java 8的Optional的更多相关文章
- 如何更规范化的编写JAVA 代码
如何更规范的编写JAVA代码 一.MyBatis 不要为了多个查询条件而写 1 = 1 当遇到多个查询条件,使用where 1=1 可以很方便的解决我们的问题,但是这样很可能会造成非常大的性能损失, ...
- map和flatmap的区别+理解、学习与使用 Java 中的 Optional
转自:map和flatmap的区别 对于stream, 两者的输入都是stream的每一个元素,map的输出对应一个元素,必然是一个元素(null也是要返回),flatmap是0或者多个元素(为n ...
- 理解、学习与使用 Java 中的 Optional
从 Java 8 引入的一个很有趣的特性是 Optional 类.Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) -- 每个 Java 程序员都 ...
- 理解、学习与使用 JAVA 中的 OPTIONAL<转>
从 Java 8 引入的一个很有趣的特性是 Optional 类.Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都 ...
- Java 8 (9) Optional取代null
NullPointerException,大家应该都见过.这是Tony Hoare在设计ALGOL W语言时提出的null引用的想法,他的设计初衷是想通过编译器的自动检测机制,确保所有使用引用的地方都 ...
- 理解、学习与使用 JAVA 中的 Optional【转载】
这是一篇转载的文章.刚学java的时候看了好久这个Optional,但一直是懵的.今天又又遇到了,重新回来再看的时候,发现并没有那么难道那个. 转载的文章再开头处写了一个对于理解Optional很关键 ...
- JAVA 中的Optional (臭名昭著的空指针异常(NullPointerException))
从 Java 8 引入的一个很有趣的特性是 Optional 类.Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) -- 每个 Java 程序员都 ...
- Tomcat上java.lang.IllegalStateException: Optional int parameter 'id' is not present
今日, 本人在tomcat+spring mvc平台的服务器上遇到java.lang.IllegalStateException: Optional int parameter 'id' is not ...
- Java 8 之 Optional
Java 8 之 Optional 背景介绍:在我们实际开发中,经常会遇到各种 NullPointerException 报错,为了避免此类问题,需要在业务代码上添加各种if判断,使代码看起来很臃肿, ...
随机推荐
- 1、javaweb学习之配置文件web.xml
今天这里主要讲述javaweb中的配置文件web.xml中的内容及其作用,都是基础部分,对于初学者需要好好掌握理解. 简单配置: <servlet> <servlet-name ...
- ES6 Proxy的应用场景
一.相关API Proxy Reflect 二.Proxy应用场景 1.数据校验 表单提交的时候做数据校验,例如年龄是不是满足条件,数据类型是不是满足要求等等,这场场景非常适合使用Proxy. 下面展 ...
- [转]安装 Silverlight 5/silverlight4 出错的解决方法
安装Silverlight 5时,如果 如图: 安装Silverlight 5时,如果你的VS不是英文版,那么可能会出现以下错误: Visual Studio 2010 SP1 that matche ...
- iOS.AutomatePackageBuild.0-Resource-List
1. xcodebuild xcodebuild: 构建Xcode project和workspace. 2. TN2339: Building from the Command Lline with ...
- Win10传递优化设置技巧
什么是“传递优化缓存” “传递优化”是微软为了加快Windows更新和Microsoft Store应用更新的下载速度,而在Windows10中引入的一种“自组织分布式本地化缓存”设计,可以在用户电脑 ...
- Tinyos学习笔记(三)
读取Telosb内部传感器数据,并在计算机上显示. senseC.nc代码如下: #include "Timer.h" #include "sense.h" # ...
- 拍照一分钟,修图两小时,PS大神是这样修片的!
乌克兰有一个叫Viktoria Solidarnyh的美图艺术家,这个艺术家有一个特别的技能——P图,她P的图,水平真的非常赞...来感受一下.... 瞬间变成魔幻田园风... 编辑:千锋UI设计 ...
- UI设计中颜色的前进色与后退色
暖色调的颜色属于前进色.膨胀色可以使物体的视觉效果变大,而收缩色可以使物体的视觉效果变小. 颜色的另外一种效果.有的颜色看起来向上凸出,而有的颜色看起来向下凹陷,其中显得凸出的颜色被称为前进色,而 ...
- JDK 之 NIO 2 WatchService、WatchKey(监控文件变化)
JDK 之 NIO 2 WatchService.WatchKey(监控文件变化) JDK 规范目录(https://www.cnblogs.com/binarylei/p/10200503.html ...
- SQL Server 查询中文字段返回为空
昨晚维护系统数据时,遇到个奇怪现象.明明数据库里有数据,查询结果就是返回为空.具体情况是这样的,查询工作日志表里关于工作描述的情况,以中文内容匹配工作描述字段,其中匹配内容里包含有空格. 尝试去掉第一 ...