Java8中Optional操作的实际应用
目录
- 简介
- 正文
- 1. Optional是什么
- 2. 没它 VS 有它
- 3. 核心操作
- 4. 应用
- 总结
- 总结
简介 目的:Optional的出现主要是为了解决null指针问题,也叫NPE(NullPointerException)
外形:Optional外形酷似容器(其实它就是一个容器),只是这个容器比较特殊,因为它只能存放一个对象,运气不好的话这个对象还是个null
操作:Optional从操作上来看,又跟前面的Stream流式操作很像,比如过滤filter - 提取map等
下面我们用比较简单的例子来对比着看下,Optional的一些基础用法
正文
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.namepublic 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为null,则创建空的Optional 对象.ofNullable(c)// 提取name,这里要注意,即使c==null,这里也不会抛出NPE,而是返回空的Optional,所以在处理数据时,我们不需要担心空指针异常.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 value 到 Optional 的属性中;如果 value=https://www.it610.com/article/=null,则抛出NPEOptional of(T value) - (默认null)
public static
:填充 T value 到 Optional 的属性中;如果引用为null,则填充nullOptional ofNullable(T value) - (构造一个空的Optional)
public static
:单纯地创建一个数据为null的空Optional,即直接填充null到 Optional 的属性中【不常用】Optional empty()
- (提取)
public Optional map(Function super T, ? extends U> mapper)
:提取Optional中属性T的某个属性值U,并将U填充到新的Optional中并返回 - (过滤)
public Optional
:过滤Optional中属性T的某个属性值,符合条件则将T填充到新的Optional中并返回filter(Predicate super T> predicate) - (扁平化提取)
public Optional flatMap(Function super T, Optional> mapper)
:提取Optional中属性T的某个属性Optional
,直接返回
public T orElse(T other)
:获取数据,如果数据为null,则返回T otherpublic T orElseGet(Supplier extends T> other)
:获取数据,如果数据为null,则通过函数式接口other返回一个新的数据Tpublic T get()
:获取数据,如果数据为null,则报NPE【不常用】
其他的就不举了,这里主要说下map()和flatMap()
如下图所示:
map()主要是提取Optional中的属性C的属性name,然后再包装到新的Optional
输入
Optional
, 输出Optional
(即Optional文章图片
String nameNew = Optional.ofNullable(c).map(c1->c1.getName()).orElse("xxx");
flatMap()主要是提取Optional中的属性B的
Optional
属性中的C的值,然后再包装到新的Optional输入
Optional
,输出Optional
文章图片
public class FlatMapDemo {private static final String DEFAULT_NAME = "javalover"; public static void main(String[] args) {getName(null); }// 取出 b.c.namepublic static void getName(B b){C c = Optional.ofNullable(b)// 这里扁平化处理,提取Optional中的C// 如果用map,则返回的是Optional >.flatMap(b->b.getC()).orElse(new C("xxx")); System.out.println(c.getName()); }}class B{private Optional c; public Optional 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可能为null;从编码角度来讲,主要是应用在非空判断;但是实际场景的话,有两个
- 没有用Optional进行包裹的参数:比如上面讲到的例子,传来的参数就是普通对象,我们就需要自己用Optional容器来包裹传来的参数,然后进行后续操作
// 取出c.namepublic static void getName(C c){// 自己手动包装 OptionalString nameNew = Optional.ofNullable(c).map(c1->c1.getName()).orElse(DEFAULT_NAME); System.out.println("new: "+nameNew); }
- 有用Optional进行包裹的参数:比如数据库查询时,我们可以用Optional来包裹查询的结果并返回,这样我们分析结果的时候,只需要通过orElse()来获取,同时还可以设定默认值
// 返回Optional,通过.orElse(defaultCar)就可以获取返回值,如果返回值为null,还可以设定一个默认值defaultCarOptional selectOne(SelectStatementProvider selectStatement);
总结
- Optional是什么:一个容器,存放一个对象,对象可以为null
- 没它 VS 有它:看场景
- 如果只是单个的if/else判断,那就没它会好点;
- 如果嵌套比较多,或者本来传来的数据就是Optional类型,那肯定是Optional合适
- 如果只是单个的if/else判断,那就没它会好点;
- 核心操作:不常用的这里就不写了
- 保存数据:工厂方法
of()
和ofNullable()
- 处理数据:map(), filter(), flatMap()
- 获取数据:orElse()
- 保存数据:工厂方法
- 应用:主要用在非空判断,实际场景的话,我们可以用在数据库查询语句中
推荐阅读
- vue中keep-alive组件实现多级嵌套路由的缓存
- JavaScript中的Map数据结构详解
- 公司的开发需求|点击《el-table》让选中的行变色,亲测实用
- 在 Android TV 上构建优秀的播放体验|中文字幕视频
- 前端-CSS篇|CSS水平垂直居中的几种方式,CSS定位
- 知识管理在企业竞争发展中的作用
- P1030
- 利用PyQt5中QLabel组件实现亚克力磨砂效果
- Python调用MySQLdb插入中文乱码的解决
- 二叉树|二叉树的 前序 中序 后序,面试题小计 根据中序 后序 得出前序