java8学习:Optional的简单使用
内容来自《 java8实战 》,本篇文章内容均为非盈利,旨为方便自己查询、总结备份、开源分享。如有侵权请告知,马上删除。
书籍购买地址:java8实战
-
如下代码
public class Person { private Car car; public Car getCar() { return car; } } public class Car { private Insurance insurance; public Insurance getInsurance() { return insurance; } } public class Insurance{ private String name; public String getName() { return name; } } //将要使用的代码 public String getCarInsuranceName(Person person){ return person.getCar().getInsurance().getName(); }
-
如上代码如果使用,如果某个Person没有车,那么就会引发空指针异常,在平常我们使用if来去判断的,比如
public String getCarInsuranceName(Person person){ if (null != person){ Car car = person.getCar(); if (null != car){ Insurance insurance = car.getInsurance(); if (insurance != null) { return insurance.getName(); } } } return "UnKnow"; }
-
或者更容易读的是这样的,避免了if的嵌套难以阅读
public String getCarInsuranceName(Person person){ if (person == null) { return "UnKnow"; } Car car = person.getCar(); if (car == null){ return "UnKnow"; } Insurance insurance = car.getInsurance(); if (insurance == null) { return "UnKnow"; } return insurance.getName(); }
- 如上null的解决办法使用中的,并且不容易阅读,java8使用了Optional来解决null问题
- Optional只能包含一个对象,对象存在的时候,Optional只是对对象的简单封装,如果没有对象,那么缺失的值被建模成一个空的Optional对象,有方法Optional.empty()返回
- null和Optional的区别:null一定会触发空指针异常,而Optional.empty()就没有事,因为他是一个有效对象,是Optional 的单一实例.
-
使用Optional重新定义bean对象
public class Person { private Optional<Car> car; public Optional<Car> getCar() { return car; } } public class Car { private Optional<Insurance> insurance; public Optional<Insurance> getInsurance() { return insurance; } } public class Insurance{ private String name; //公司肯定有名字 public String getName() { return name; } }
- 上面中Person中的car类型是Optional,很明确的表达了Person可能有car对象也可能没有,同样对car的引用做了保证,有car的话就是car对象,没有car 的话就是Optional.empty()
- Insurance中name并没有加Optional,因为公司肯定是有名字的,如果name为空只能代表参数是错误的,而这里如果加上Optional只能掩盖错误发生
Optional的创建
- 空对象:
Optional.empty()
- 依靠一个非空对象创建Optional:
Optional.of(notnullobj)
,如果notnullobj是一个空对象,那么就会抛出空指针异常 - 可接受null对象的Optional:
Optional.ofNullable(car)
,car对象可以是空对象也可以不是空对象,如果是空对象则得到一个空的Optional
使用map从Optional中提取和转换值
String name = null; if (insurance != null){ name = insurance.getName(); }
-
如上是原来的提取的代码,先判断在取值,避免空指针,如下使用Optional
Optional<String> name = Optional.ofNullable(insurance).map(Insurance::getName);
- map函数会应用于流的每个元素上,然后返回name,可以把Optional看作是一个特殊的集合数据,至多包含一个元素,如果insurance包含值,那么就交给map处理,否则返回空Optional,就什么也不做
-
本文开头提到的这样一连串的调用,怎么用Optional解决呢?
//原来 public String getCarInsuranceName(Person person){ return person.getCar().getInsurance().getName(); }
- 我们是用如下代码可不可以呢 ?
public String getCarInsuranceName(Optional<Person> person){ person.map(Person::getCar) .map(Car::getInsurance) .map(Insurance::getName); }
- 如上代码是编译通过不了的,因为person对象是一个Optional对象,那么他调用map将会返回一个Optional>,这显然是错误的
- 之前我们在Stream遇到同样的问题,当时是用flatMap解决的,在这同样适用,如下
public String getCarInsuranceName(Optional<Person> person){ return person.flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknow"); }
- 如上我们很清楚的就可以知道哪些对象可能是null,并且省去了if语句的平判断,在最后orElse:如果map得到的是null,那么就会有默认的UnKnow替代null,以防止发生空指针
Optional无法序列化
-
为什么?
- 如上代码中我们展示了使用Optional去构建bean,将允许缺失或者暂时无定义的变量值用特殊的形式标记出来,但是Optional的设计初衷并不是这样的,它的设计初衷仅仅是要支持能返回Optional的语法,由于它设计时就没有考虑将其作为类的字段使用,所以它也并未实现序列化接口,所以如果在框架或者序列化库中使用了 Optional修饰字段,那么可能会引发错误
- 但是如上我们看到了,Optional应用到bean中也是不错的,能够清楚的反映出那些字段是有可能为null的,并且可以使用Optional的特性,可以这样在bean中应用Optional
public class Car { private Insurance insurance; public Optional<Insurance> getInsuranceAsOptional() { return Optional.ofNullable(insurance); } }
使用filter剔除特定的值
-
如果需要判断某个公司,那么我们需要这样的判断
Insurance insurance = ...; if (null != insurance && "lalala".equals(insurance.getName())){ System.out.println("..."); }
-
使用filter方法
Optional<Insurance> insurance = null; insurance.filter(i -> "lalala".equals(i.getName())) .ifPresent(i -> System.out.println("..."));
- 如上的ifPresent方法是判断i是否是空值,不是空值就执行后面的输出,是空即什么都不做
异常与Optional对象
- String转换为Integer对象,如果转换错误就会爆数字格式化异常,我们必须try上异常以处理异常
-
需求:输入参数转换为int,然后返回该转换后的值,出错的话就返回0
public Integer StringParse(String str){ if (null == str) return 0; try { return Integer.parseInt(str); }catch (NumberFormatException e){ return 0; } }
-
用Optional解决
public Optional<Integer> StringParse(String str){ try { return Optional.of(Integer.parseInt(str)); }catch (NumberFormatException e){ return Optional.empty(); } }
避免使用基本类型的Optional对象
- 对于之前的函数式接口,我们提到的如果基本类型比较多,那么就优先使用对应的基本类型的函数式接口,比如IntFunction,但是Optional不推荐使用OptionalInt等类似的基本类型对象,因为这些对象中并没有map和filter等方法
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python连接SQLite
Python 连接 SQLite 记录自己学习Python的代码。每天进步一点点,目标距离缩小点。 #! /usr/bin/python3 #-*- coding: utf-8 -*- import sqlite3 # 在 磁盘上创建数据库 # with sqlite3.connect('\\workspace\\PycharmProjects\\DB\\sqlite\\test1.db') as conn: # 在内存中 创建数据库 # 可以通过使用with语句来省去显示的调用close方法关闭连接和游标 with sqlite3.connect(':memory:') as conn: # conn 数据库连接对象,并返回数据库连接 print("Opened database successfully") # 创建游标 c = conn.cursor() # 执行SQL语句 c.execute('''CREATE TABLE COMPANY (ID INT PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, AGE INT NOT NULL, AD...
- 下一篇
课程目录of NOIP大神培养计划
NOIP C++ 大神培养计划课程目录: Step1:基础算法:模拟、排序、递推、递归、贪心、二分 Step2:基础数据结构:栈、队列、优先队列、树与二叉树 Step3:数学基础 Step4:搜索算法:深度优先搜索,广度优先搜索,迭代加深搜索,A,IDA算法 Step5:图论基础:图的储存,遍历,最短路算法,最小生成树算法,最近公共祖先 Step6:动态规划 Step7:高级数据结构:哈希表(散列表),并查集,线段树,树状数组,伸展树,Treap,平衡树,后缀树与后缀树组,树链剖分。 Step8:图论高级:基环树,差分约束,Tarjan算法,二分图。 我们预计用一年的时间详细介绍完这些内容,并为未来的NOIP做准备。 在讲解理论之后,我们会附加许多习题,加以练习,并附上详细题解。 课程主要参考资料:算法竞赛进阶指南,高级数据结构,信息学奥赛数学一本通,大家可以购买以作辅助。 课后练习均来自 洛谷https://www.luogu.org/大家可以注册并在上面练习。 这就是今天的内容。下次我们要来讲最基础的,也是极为重要的——模拟算法。 我们下次见!
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8编译安装MySQL8.0.19
- CentOS关闭SELinux安全模块
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- 设置Eclipse缩进为4个空格,增强代码规范
- Windows10,CentOS7,CentOS8安装Nodejs环境