java中Optional的应用,以及map和flatMap的区别
创始人
2024-03-25 02:37:02
0

关于Option的介绍可以看深入理解java8中的Optional 类就可以了,但是复杂一点的使用在网上却没有搜到,这里结合我开发时遇到的真实案例来讲一下Option的使用。

1.案例一

        在真实业务操作过程中,都是对象里面套对象,这边先简单定义操作对象:

public class PictureCondition {private String url;public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}}

       在这里先一个简单的对象,里面也就只有一个属性,在Controller层需要接收一个PictureCondition的对象,应判断这个对象里面的url属性是否为空,或者是有空格出现,如果有的话,则抛出一个异常。

      使用一般的写法是这样判断的:

if(pictureCondition==null||pictureCondition.getUrl()==null||"".equals(pictureCondition.getUrl().trim())){throw new RuntimeException("出错啦");}

      使用Option的写法是这样的:

Optional.ofNullable(pictureCondition).map(PictureCondition::getUrl).map(String::trim).filter(x -> !"".equals(x)).orElseThrow(() -> new RuntimeException("出错啦"));

      对于单层循环使用一般的写法还是可以应对的,但是当层数比较多时,这样写就不太好了。

2.案例二

先定义操作对象

1.定义User对象

public class User {//用户名称private String username;//当前用户的订单信息private List orders;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public List getOrders() {return orders;}public void setOrders(List orders) {this.orders = orders;}
}

2.定义订单对象

public class Order {//订单idprivate Long orderId;//订单时间private Date createTime;public Long getOrderId() {return orderId;}public void setOrderId(Long orderId) {this.orderId = orderId;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}
}

具体场景:

        当在一个方法里面需要拿到user对象(可能为空)里面是的orders对象,如果当前orders对象为空,则返回一个空的list对象。

写法:

        Java8之前的写法,我们需要先判断user对象是否为null,不为空的话,获取当orders对象是否为空,为空则返回一个空的list

if(user!=null && user.getOrders!=null) {return user.getOrders();
} else {return Collections.emptyList();
}

        使用Java8的写法,那么就不需要这样判断了,直接看代码:

return Optional.ofNullable(user).map(u -> u.getOrders()).orElse(Collections.emptyList())

扩展思考:

        Optional.map 是可以无限级联的, 比如再深一层, 获得用户名的大写形式

return Optional.ofNullable(user).map(u -> u.getUsername()).map(name -> name.toUpperCase()).orElse(null);

这要搁在以前, 每一级调用的展开都需要放一个 null 值的判断

User user = .....
if(user != null) {String name = user.getUsername();if(name != null) {return name.toUpperCase();} else {return null;}
} else {return null;
}

3.Optional中的map和flatMap的区别

源码:

map会将传入的Function函数的结果进行封装,先看源码:

    public Optional map(Function mapper) {Objects.requireNonNull(mapper);if (!isPresent())return empty();else {return Optional.ofNullable(mapper.apply(value));//会使用Optional的ofNullable方法包装Function函数返回的值}}

flatMap会直接返回Function函数执行的结果,看源码:

    public Optional flatMap(Function> mapper) {Objects.requireNonNull(mapper);if (!isPresent())return empty();else {return Objects.requireNonNull(mapper.apply(value));//直接返回Function执行的结果}}

      这样看,好像也看不出来两者太大的区别,不知道什么时候用map,什么时候用flatMap,通过下面的案例进行具体分析

map和flatMap的用法区别

首先对于下列对象的操作

public class School {private String name;private Optional tearch;  //属性为Option封装的Tearch对象public String getName() {return name;}public void setName(String name) {this.name = name;}public Optional getTearch() {return tearch;}public void setTearch(Optional tearch) {this.tearch = tearch;}
}class Tearch{private String name;private Optional student;public String getName() {return name;}public void setName(String name) {this.name = name;}public Optional getStudent() {return student;}public void setStudent(Optional student) {this.student = student;}
}class Student{private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

   这时,如果给你一个School对象,让你得到Student的name属性的值,可以使用下面的方式:

public static String getStudentName(School school){return Optional.ofNullable(school).map(School::getTearch).map(Tearch::getStudent).map(Student::getName).orElse("false");}

 你可能感觉这样写很对啊,没毛病,可惜这段代码连编译都不会通过的,我们思考一下,School::getTearch会返回School实例的tearch属性,而tearch属性是使用Optional包装的Tearch对象,所以使用了map(School::getTearch),会返回Optional>对象,而不是我们所想的Optional,这是你可能想自己试一下,我已经做了截图,毕竟有图有真相。

20191119203530875.png

2019111920380750.png

这时就可以使用flatMap来解决这个问题,刚才已经说了,flatMap不会使用Optional包装Function执行的返回结果,所以我们可以使用flatMap来解决这个问题。

    public static String getStudentName(School school){return Optional.ofNullable(school).flatMap(School::getTearch).flatMap(Tearch::getStudent).map(Student::getName).orElse("false");}

看截图:

20191119204122472.png

       这时map和flatMap的用法就清楚,如果某对象实例的属性本身就为Optional包装过的类型,那么就要使用flatMap方法,就像School::getTearch返回的就是Optional类型的,所以不用再使用Optional进行包装,这时就要选用flatMap方法,对于返回值是其他类型,需要Optional进行包装,如Student::getName得到是String类型的,就需要使用map方法在其外面包装一层Optional对象。

注意:Option类是判断空指针异常时用的,对于其他的if..else只要不是判断空指针的问题,就不要使用Option类,lz就陷入了一个误区,以为学了Option类,看见if...else就往Option来想,这么做真是大作特错。用Option的情况时在判断值是否为null时,Option就发挥作用了。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...