java8出来也有一段时间了,不知大家用得还顺手否?如果已经习惯于使用Lambda表达式和Stream流的人一定会经常发现一个特殊的对象:Optional类。今天我要聊的内容都跟Optional这个类有关。
好了,废话不多说,下面进入正题。
Optional是什么
对于Optional是个什么,大家不要想得太复杂。简单得说,就是Java8中新增的一个类,经常配合Stream流和Lambda表达式来使用的类。
那么java8为啥要新增这么一个类呢?总不会是吃饱了撑得没事干吧,所以既然你在java8中看到了它,说明必然有其存在的意义。
至于存在意义为何,我现在也不是很清楚。有种说法叫避免空指针异常问题。我觉得这种说法有点扯。因为我试了几次,如果你不做任何的判断,该抛的异常依然存在。只不过在避免非空问题的处理上确实比传统方式顺眼许多。
下面我将使用一个例子来简单演示一下传统避免空指针和使用Optional避免控制针,代码示例如下:
![9ca93a934a35c8f5bddd53057be90c59.png](https://img-blog.csdnimg.cn/img_convert/9ca93a934a35c8f5bddd53057be90c59.png)
由上图可知,使用Optional后,避免空指针异常的方式会更加顺眼。至少我是这么觉得的。
既然简单扯了一下何为Optional,那么接下来就该详细说说Optional的用法了。
Optional对象获取
首先我们要能拿到一个Optional对象,那么Optional对象又该如何拿到呢?目前获取Optional类对象的方式有三种:of方法,ofNullable方法和empty方法。
下面的例子演示了三种获取Optional对象的方式:
![5a33350a2d6803db220f1b379b06e817.png](https://img-blog.csdnimg.cn/img_convert/5a33350a2d6803db220f1b379b06e817.png)
那么这三种获取Optional对象的方式有何区别呢?这个可以从源码中找到答案。
of方法的源码如下:
![4c288827ce11ab23faf638d1d90bed7d.png](https://img-blog.csdnimg.cn/img_convert/4c288827ce11ab23faf638d1d90bed7d.png)
ofNullable方法的源码如下:
![abf643ef1229b18b878338dddee0a580.png](https://img-blog.csdnimg.cn/img_convert/abf643ef1229b18b878338dddee0a580.png)
empty方法的源码如下:
![849cfef21e0ac3a51fbfa3be71ffa8c5.png](https://img-blog.csdnimg.cn/img_convert/849cfef21e0ac3a51fbfa3be71ffa8c5.png)
通过对比可以发现,of方法获取Optional对象时,要求传入的值不能为空,而ofNullable则允许传入值的为空,只不过值为空时,构造的是一个Optional的值为空的对象。而empty方法则直接获取一个值为空的Optional对象。
Optional对象的常用方法
既然已经能拿到Optional对象,那么就可以调用该对象自带的一系列方法了。由于本人的JDK为13,所以哪些方法在JDK8上没有,也记得不是很清,所以大家可以先熟练掌握JDK8中能用的,至于别的至少先混个脸熟。
Optional常用的方法如下:
- isEmpty方法
isEmpty方法用来判断该Optional对象中存储的值是否为空,为空返回true,不为空返回false。
isEmpty的示例代码如下:
![0e7a3cfa206e468e552ad7e866f2d238.png](https://img-blog.csdnimg.cn/img_convert/0e7a3cfa206e468e552ad7e866f2d238.png)
执行结果如下:
![b122acf61965f148b96265e614f408dc.png](https://img-blog.csdnimg.cn/img_convert/b122acf61965f148b96265e614f408dc.png)
- isPresent方法
isPresent方法也是用来判断Optional对象中存储的值是否不为空的,当Optional对象中存储的值不为空时返回true, 为空时返回false,其判断结果与isEmpty的判断结果相反。
isPresent方法的示例代码如下:
![5c146b3ef110de9f193bcd9f71beead4.png](https://img-blog.csdnimg.cn/img_convert/5c146b3ef110de9f193bcd9f71beead4.png)
执行结果如下:
![52e060b0c8f578111a5c6fa2f6b5be6c.png](https://img-blog.csdnimg.cn/img_convert/52e060b0c8f578111a5c6fa2f6b5be6c.png)
- get方法
get方法用来获取Optional中存储的对象值,如果存储的的值为空,则会抛出异常。
get方法的示例代码如下:
![5511725e6c2ae4f08a1e2aea55032d94.png](https://img-blog.csdnimg.cn/img_convert/5511725e6c2ae4f08a1e2aea55032d94.png)
执行后结果如下:
![6f19d953be8afb9c590bff6346a3b2a2.png](https://img-blog.csdnimg.cn/img_convert/6f19d953be8afb9c590bff6346a3b2a2.png)
- orElse方法
orElse方法也可以获取Optional对象中存储的值,与get不同之处在于,当存储值为空时,会返回orElse传入值,而非抛出异常。
orElse方法的示例代码如下:
![ef8c15fd248b3295660aeaee31cf366c.png](https://img-blog.csdnimg.cn/img_convert/ef8c15fd248b3295660aeaee31cf366c.png)
执行结果如下:
![1f2ede5ee60d305d90a3b9487f262d3f.png](https://img-blog.csdnimg.cn/img_convert/1f2ede5ee60d305d90a3b9487f262d3f.png)
- or方法
or方法会先判断当前Optional对象存储的值是否为空,不为空则依然返回当前对象,若为空,则根据传入的生产者对象来获取另一个Opitonal对象。当然,通过该生产者对象产生的Optional对象中存储的值不能为空。
or方法的示例代码如下:
![1be675716a4389fc816ec7705da045ef.png](https://img-blog.csdnimg.cn/img_convert/1be675716a4389fc816ec7705da045ef.png)
执行后结果如下:
![5a352e03757110a6d8371ec578afc76d.png](https://img-blog.csdnimg.cn/img_convert/5a352e03757110a6d8371ec578afc76d.png)
- orElseGet方法
orElseGet方法和orElse方法有些类似,都是当Optional对象存储的值为空,根据传入的参数来计算返回值。区别在于orElseGet是根据传入的生产者对象来获取,而orEles是直接将传入的值返回。
orElseGet方法的示例代码如下:
![c354ace21e3a7293658f7390e949fa06.png](https://img-blog.csdnimg.cn/img_convert/c354ace21e3a7293658f7390e949fa06.png)
执行结果如下:
![7bec21d6627da5000418d1830d112060.png](https://img-blog.csdnimg.cn/img_convert/7bec21d6627da5000418d1830d112060.png)
- orElseThrow方法
orElseThrow方法的作用是当Optional对象存储的值为空的时候抛出一个异常,当然,若Optional对象存储的值不为空的时候,正常返回。orElseThrow有两个重载版本:一个无参的,一个带参的。无参抛出的是默认的异常,而带参的则会抛出指定的异常。
orElseThrow方法示例代码如下:
![8d8e6d070b4c62cf966a6d1604b1f4d6.png](https://img-blog.csdnimg.cn/img_convert/8d8e6d070b4c62cf966a6d1604b1f4d6.png)
执行结果如下图:
![c46ea78cc43103a03fe48ee5c114203e.png](https://img-blog.csdnimg.cn/img_convert/c46ea78cc43103a03fe48ee5c114203e.png)
- filter方法
filter方法是用来判断该Optional对象中存储的值是否符合传入的判断条件。
若该Optional对象中存储的值为空,则依然返回该对象。当Optional对象中存储的值不为空时,进行条件判断,满足则返回该对象,不满足则返回一个空对象。
filter方法的示例代码如下:
![579229a7edfccb40c2cfc322962375f2.png](https://img-blog.csdnimg.cn/img_convert/579229a7edfccb40c2cfc322962375f2.png)
执行结果如下图:
![91333a957dc9649773bcfcb6a3178f00.png](https://img-blog.csdnimg.cn/img_convert/91333a957dc9649773bcfcb6a3178f00.png)
- ifPrsent
ifPresent方法的作用是,当Optional对象存储的值不为空时,通过传入的消费者对象对该值进行处理。若存储值为空,则不做任何处理。
ifPresent方法示例代码如下:
![3fe5e170a18f2ed8c5b81f1a847f2e00.png](https://img-blog.csdnimg.cn/img_convert/3fe5e170a18f2ed8c5b81f1a847f2e00.png)
执行结果如下:
![8f2eee875c6713bc14431cf8da9eedef.png](https://img-blog.csdnimg.cn/img_convert/8f2eee875c6713bc14431cf8da9eedef.png)
- ifPresentOrElse
ifPresentOrElse方法的作用与ifPresent方法有些类似,都是当Optional中存储的值不为空时,使用传入的生产者对象进行处理,区别在于ifPresentOrElse多传入了一个线程执行体对象-Runnable, 当Optional中存储的值为空时,执行该线程执行体,当然,仅仅是作为普通方法调用。至于我为何会这么说,可以看如下源码:
![d12d517e7c04eed1274492fc4d1e40c8.png](https://img-blog.csdnimg.cn/img_convert/d12d517e7c04eed1274492fc4d1e40c8.png)
从源码中可知,这里是直接调用的run方法,而开启新线程执行的前提是,需要用Thread类对象接收Runnable对象,并调用Thread类对象的start方法才可以。
下面给出ifPresentOrElse的示例代码:
![f74f2d9ad5c92525bad21527968f77ea.png](https://img-blog.csdnimg.cn/img_convert/f74f2d9ad5c92525bad21527968f77ea.png)
执行结果如下图所示:
![3c481d09ccfcffbe8b933d731161452e.png](https://img-blog.csdnimg.cn/img_convert/3c481d09ccfcffbe8b933d731161452e.png)
- map
map方法是当Optional中存储的值不为空时,将其转换为另一种类型值的Optional对象。
map方法的示例代码如下:
![0090fcba8079e140a6b4de7ab8b6d9de.png](https://img-blog.csdnimg.cn/img_convert/0090fcba8079e140a6b4de7ab8b6d9de.png)
执行结果如下:
![6a55e772225406a8400b265fa5c0cfc2.png](https://img-blog.csdnimg.cn/img_convert/6a55e772225406a8400b265fa5c0cfc2.png)
- flatMap
flatMap方法的作用与map方法类似,都是讲当前Optional对象中存储的值经过转换后生成另一个Optional对象,区别在于map只需要提供转换Optional对象中值的转换器即可,而flatMap则必须提供对Optional对象中值的处理并且转换为哪种Optional对象的方法。
flatMap方法的示例代码如下:
![420e8ba637a3fdd7b71cb2cf7965d1f1.png](https://img-blog.csdnimg.cn/img_convert/420e8ba637a3fdd7b71cb2cf7965d1f1.png)
执行结果如下:
![c5269fd7e90722804fdfb37998db05a8.png](https://img-blog.csdnimg.cn/img_convert/c5269fd7e90722804fdfb37998db05a8.png)
- stream方法
stream方法的作用是将Optional对象转换为Steam流对象。关于何为Stream流对象,也是Java8新增特性,这里就不过多介绍。
stream方法的示例代码如下:
![4a4b726c3e6a4bf0f87a27e8f55834d3.png](https://img-blog.csdnimg.cn/img_convert/4a4b726c3e6a4bf0f87a27e8f55834d3.png)
执行结果如下图所示:
![d1d3425491594b2015bb8dd83011d052.png](https://img-blog.csdnimg.cn/img_convert/d1d3425491594b2015bb8dd83011d052.png)
最后,需要提一点的是,Java中还有与Optional类似的专门用来处理Double的OptionalDouble,专门用于处理int的OptionalInt和专门用于处理long的OptionalLong这三个类。其获取方式和常用方法与Optional的方式都大同小异,故不再过多介绍。大家只要类比以一下就能掌握。