作者:汤圆
集体博客:javalover.cc
前言
官人们好啊,我是汤圆,明天给大家带来的是《Java8中的Optional操作》,心愿有所帮忙,谢谢
文章纯属原创,集体总结不免有过错,如果有,麻烦在评论区回复或后盾私信,谢啦
最近看到有几个粉丝了(窃喜),多的话我也不说了,欢送退出咱们的荣华富贵小家庭
简介
目标:Optional的呈现次要是为了解决null指针问题,也叫NPE(NullPointerException
)
形状:Optional形状酷似容器(其实它就是一个容器),只是这个容器比拟非凡,因为它只能寄存一个对象,运气不好的话这个对象还是个null
操作:Optional从操作上来看,又跟后面的Stream流式操作很像,比方过滤filter – 提取map等
上面咱们用比较简单的例子来比照着看下,Optional的一些根底用法
先来看下目录
目录
- Optional是什么
- 没它 VS 有它
- 外围操作
- 利用
注释
1. Optional是什么
Optional是一个容器,只能寄存一个对象(可为null)
Optional的呈现是
- 一个是为了解决NPE问题(阿里开发手册也有提到这一点,点击可间接下载,官网链接)
- 另一个是为了代码更加清晰可读,因为Optional这个名字的灵感就是来自英文
optional
(可选的),意思就是说这个对象能够为空,能够不为空
2. 没它 VS 有它
上面咱们用旧代码和新代码来比照着看(所谓的新旧是以Java8为分割线)
案例1:现有C类,咱们要提取C.name属性
public class OptionalDemo {
private static final String DEFAULT_NAME = "javalover";
public static void main(String[] args) {
// 传入null,以身试法
getName(null);
}
// 取出c.name
public static void getName(C c){
// 旧代码 Java8之前
String name = (c!=null ? c.getName() : DEFAULT_NAME);
System.out.println("old: "+name);
// 新代码 Java8之后(上面的三个操作方法前面会介绍,这里简略理解下)
String nameNew = Optional
// 工厂办法,创立Optional<C>对象,如果c为null,则创立空的Optional<C>对象
.ofNullable(c)
// 提取name,这里要留神,即便c==null,这里也不会抛出NPE,而是返回空的Optional<String>,所以在解决数据时,咱们不须要放心空指针异样
.map(c1->c1.getName())
// 获取optional的属性值,如果为null,则返回给定的实参DEFAULT_NAME
.orElse(DEFAULT_NAME);
System.out.println("new: "+nameNew);
}
}
class C{
private String name;
public C(String name) {
this.name = name;
}
// 省略getter/setter
}
乍一看,如同Java8之前的旧代码更适合啊,只须要一个三目运算符
再看Optional操作,发现并没有那么简洁
是这样的,如果只是一层判断,那一般的if判断做起来更不便;
然而如果嵌套两层呢,比方b.getC().getName()?
上面咱们就看下,两层嵌套会怎么样
例子2:现多了一个B类(依赖C类),咱们要从对象B中提取C的属性name,即b.getC().getName()
public static void getName2(B b){
// 旧代码
String name = (b!=null ? ( b.getC()!=null ? b.getC().getName() : DEFAULT_NAME) : DEFAULT_NAME);
// 新代码
String nameNew = Optional
.ofNullable(b)
.map(b1->b1.getC())
.map(c1->c1.getName())
.orElse(DEFAULT_NAME);
System.out.println(nameNew);
}
class B{
private C c;
public B(C c) {
this.c = c;
}
// 省略getter/setter
}
这次不论是乍一看,还是始终看,都是Optional更胜一筹
例子3:现多了一个A类(依赖B类),咱们要提取a.getB().getC().getName()
等等等,省略号
意思到就行,反正要说的就是单从判空来看的话,Optional必定是好过三目运算符的(if/else这里就不举了,它的嵌套只会更多)
3. 外围操作
因为Optional次要是操作数据(相似数据库操作),所以咱们这里从数据的角度来进行剖析
这里咱们能够分为三种操作:保留数据、解决数据、获取数据
保留数据:
- (没有默认值)
public static <T> Optional<T> of(T value)
:填充 T value 到 Optional 的属性中;如果 value==null,则抛出NPE - (默认null)
public static <T> Optional<T> ofNullable(T value)
:填充 T value 到 Optional 的属性中;如果援用为null,则填充null - (结构一个空的Optional)
public static<T> Optional<T> empty()
:单纯地创立一个数据为null的空Optional,即间接填充null到 Optional 的属性中【不罕用】
解决数据:
- (提取)
public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
:提取Optional中属性T的某个属性值U,并将U填充到新的Optional中并返回 - (过滤)
public Optional<T> filter(Predicate<? super T> predicate)
:过滤Optional中属性T的某个属性值,符合条件则将T填充到新的Optional中并返回 - (扁平化提取)
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
:提取Optional中属性T的某个属性Optional<U>
,间接返回
获取数据:
public T orElse(T other)
:获取数据,如果数据为null,则返回T otherpublic T orElseGet(Supplier<? extends T> other)
:获取数据,如果数据为null,则通过函数式接口other返回一个新的数据Tpublic T get()
:获取数据,如果数据为null,则报NPE【不罕用】
下面这些操作中,不罕用的就是get()和empty()
其余的就不举了,这里次要说下map()和flatMap()
如下图所示:
map()次要是提取Optional中的属性C的属性name,而后再包装到新的Optional
输出Optional<C>
, 输入Optional<String>
(即Optional<c.name>)
String nameNew = Optional
.ofNullable(c)
.map(c1->c1.getName())
.orElse("xxx");
flatMap()次要是提取Optional中的属性B的Optional<C>
属性中的C的值,而后再包装到新的Optional
输出Optional<B>
,输入Optional<C>
public class FlatMapDemo {
private static final String DEFAULT_NAME = "javalover";
public static void main(String[] args) {
getName(null);
}
// 取出 b.c.name
public static void getName(B b){
C c = Optional
.ofNullable(b)
// 这里扁平化解决,提取Optional<C>中的C
// 如果用map,则返回的是Optional<Optional<C>>
.flatMap(b->b.getC())
.orElse(new C("xxx"));
System.out.println(c.getName());
}
}
class B{
private Optional<C> c;
public Optional<C> getC() {
return c;
}
public void setC(C c) {
this.c = Optional.ofNullable(c);
}
}
class C{
private String name;
public C(String name) {
this.name = name;
}
// 省略getter/setter
}
4. 利用
从标准角度来讲,是为了代码清晰,一看用Optional<T>
变量,就晓得T可能为null;
从编码角度来讲,次要是利用在非空判断;然而理论场景的话,有两个
- 没有用Optional进行包裹的参数:比方下面讲到的例子,传来的参数就是一般对象,咱们就须要本人用Optional容器来包裹传来的参数,而后进行后续操作
// 取出c.name
public static void getName(C c){
// 本人手动包装 Optional<C>
String nameNew = Optional
.ofNullable(c)
.map(c1->c1.getName())
.orElse(DEFAULT_NAME);
System.out.println("new: "+nameNew);
}
- 有用Optional进行包裹的参数:比方数据库查问时,咱们能够用Optional来包裹查问的后果并返回,这样咱们剖析后果的时候,只须要通过orElse()来获取,同时还能够设定默认值
// 返回Optional<Car>,通过.orElse(defaultCar)就能够获取返回值,如果返回值为null,还能够设定一个默认值defaultCar
Optional<Car> selectOne(SelectStatementProvider selectStatement);
总结
- Optional是什么:一个容器,寄存一个对象,对象能够为null
-
没它 VS 有它:看场景
- 如果只是单个的if/else判断,那就没它会好点;
- 如果嵌套比拟多,或者原本传来的数据就是Optional类型,那必定是Optional适合
-
外围操作:不罕用的这里就不写了
- 保留数据:工厂办法
of()
和ofNullable()
- 解决数据:map(), filter(), flatMap()
- 获取数据:orElse()
- 保留数据:工厂办法
- 利用:次要用在非空判断,理论场景的话,咱们能够用在数据库查问语句中
后记
最初,感激大家的观看,谢谢
原创不易,期待官人们的三连哟
发表回复