目录
简介
optional类是java8中引入的针对NPE问题的一种优美处理方式,源码作者也希望以此替代null。
历史
null带来的种种问题
- 错误之源。
NullPointerException是目前Java程序开发中最典型的异常。
- 代码膨胀。
它让你的代码充斥着深度嵌套的null检查,代码的可读性糟糕透顶。
- 自身是毫无意义的。
null自身没有任何的语义,尤其是,它代表的是在静态类型语言中以一种错误的方式对缺失变量值的建模。
- 破坏了Java的哲学。
Java一直试图避免让程序员意识到指针的存在,唯一的例外是:null指针。
- 在Java的类型系统上开了个口子。
null并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量。这会导致问题,原因是当这个变量被传递到系统中的另一个部分后,你将无法获知这个null变量最初的赋值到底是什么类型。
方案
汲取Haskell和Scala的灵感,Java 8中引入了一个新的类java.util.Optional<T>。这是一个封装Optional值的类。举例来说,使用新的类意味着,如果你知道一个人可能有学校也可能没有,那么Student类内部的school变量就不应该声明为Schoold,遭遇某学生没有学校时把null引用赋值给它,而是应该像本篇那样直接将其声明为Optional<School>类型。
场景引入
首先我们引入一个常见的两个场景
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
上述方式是我们常见的判读流程,optional就是针对每次空判断导致的代码欣赏性问题进行了一套解决方案
方法说明
构造函数
- Optional(T var1)
源码
?
1 2 3 4 5 6 7 8 9 |
|
从源码可知,optional的构造器私有,不能直接创建,只能通过类中的其他静态方法创建,optional构造器支持一个泛型入参,且改参数不能为空
创建Optional对象
- 声明一个空的Optional: Optional<T> empty()
- 依据一个非空值创建Optional: Optional<T> of(T var0)
- 可接受null的Optional: Optional<T> ofNullable(T var0)
源码
empty()源码
?
1 2 3 4 5 6 7 8 9 10 |
|
从源码可知,optional类中维护了一个null值的对象,使用empty静态方法即可返回该空值对象
of(T var0)源码
?
1 2 3 |
|
返回常见的有参构造对象,注意由于构造器要求入参不能为空,因此of方法的入参为空的话,依然会报NPE异常
ofNullable(T var0)源码
?
1 2 3 |
|
这个方法是对of方法的补强,当ofNullable方法的入参不为空是正常返回构造对象,当入参为空时,返回一个空值的optional对象,而不会抛出异常。
ofNullable方法大部分场景优于of的使用。
举例
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
使用map从Optional对象中提取和转换值
- Optional<U> map(Function<? super T, ? extends U> var1)
源码
?
1 2 3 4 |
|
当optional包裹的值为空时直接放回空对象,否则执行入参中的Function.apply方法
使用flatMap链接Optional对象
- Optional<U> flatMap(Function<? super T, Optional<U>> var1)
源码
?
1 2 3 4 |
|
与map几乎一致。注意的是,入参的Function.apply方法中,返回类型为optional类型
举例
?
1 2 3 4 5 6 7 8 9 10 11 |
|
默认行为及解引用Optional对象1
- T orElse(T var1)
- T orElseGet(Supplier<? extends T> var1)
- T orElseThrow(Supplier<? extends X> var1)
注:这三个方法方法不是静态方法,因此需要通过实例对象调用,一般跟在方法ofNullable后用于处理空值或返回值
源码
orElse源码
?
1 2 3 |
|
当optional中的包裹值不为空时返回包裹的值,若为空则返回orElse中的入参值
orElseGet源码
?
1 2 3 4 5 6 7 8 9 10 |
|
与上个方法类似,当optional中的包裹值不为空时返回包裹的值,若为空执行orElseGet中的Supplier方法
orElseThrow源码
?
1 2 3 4 5 6 7 |
|
类似的,当optional中的包裹值不为空时返回包裹的值,若为空抛出orElseThrow中的Supplier.get的异常方法
举例
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
默认行为及解引用Optional对象2
- boolean isPresent()
- void ifPresent(Consumer<? super T> var1)
源码
?
1 2 3 4 |
|
用户判断optional包裹的值是否为空,返回布尔值
ifPresent(Consumer var1)源码
?
1 2 3 4 5 |
|
用户处理optional包裹的值不为空时,继续处理入参中Consumer.accept的方法。类似于 if(var!=null) {do sth}
举例
?
1 2 3 4 5 6 7 8 9 10 11 |
|
使用filter剔除特定的值
- Optional filter(Predicate<? super T> var1)
源码
?
1 2 3 4 5 6 7 8 |
|
用于对optional对象的过滤,当optional包裹的值不为空时返回该值,否则执行filter入参的Predicate.test方法
举例
?
1 2 3 4 5 6 7 8 9 10 |
|
实战
关于optional类的说明大致已经讲完,再回到开始的时候,提到的场景引入,结合optional进行改造
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
附:
补充代码
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
[1] 参考自java8实战
详细源码,请参考:github.com/chetwhy/clo…
总结
到此这篇关于Java8中Optional类使用的文章就介绍到这了,更多相关Java8 Optional类使用内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://juejin.cn/post/7025925484462473246
本文链接:https://my.lmcjl.com/post/7814.html
4 评论