Java之Optional使用姿势二

Optional是一种显式地避免出现空指针的操作,就如我们在实际开发中如果遇到方法返回值是集合的情况下不是返回null,而是返回一个空的集合一样,事实上,如果方法的返回值如果是普通对象,我们也不应该返回null,而是返回一个被包装的Optional对象,例如返回Optional< User >。Optional不仅仅提供了常规的避免空指针的方法,还提供了一些简单的流式操作,能够实现一些常规的链式操作。以下,记录一些工作中的使用心得。

1、背景:

以用户管理模块举例,一个用户可能有多种角色,一个角色又可能有多种权限。当在用户管理界面希望查询到某一用户的所有角色以及权限。项目分层:Controller->Service->Repository->Mapper。

2、Optional.of()与Optional.ofNullable():

Optional.of()方法用于确定被包装的对象一定不为null的场景,而Optional.ofNullable()方法则用于不确定被包装的对象是否为null的场景

1.1、Optional.ofNullable():

场景一: 例如,在Repository层根据用户id查询用户,并不能确定数据库中是否存在要查询的user,那么使用Optional.ofNullable()返回一个Optional对象,避免在上层使用时出现空指针。

代码:

java 复制代码
public Optional<User> getUserById(Integer userId) {
    return Optional.ofNullable(userMapper.selectById(userId));
} 

场景二:例如,调用日志模块的API在用户当日所有的操作日志中找到所有修改昵称的操作,将结果组装返回成一个指定的数据结构。我们无法确保查询结果一定不为null,所以需要用Optional.ofNullable()包装。

代码:

java 复制代码
public List<OperateLogInfo> getOperateLogInfo(Integer userId) {
    // getUpdateNickNameOperation调用日志模块的API,是否为null未知
    return Optional.ofNullable(getUpdateNickNameOperation(userId))
            .orElseGet(Collections::emptyList)
            .stream()// 省略stream之后的操作
            .map()
            .filter()
            .collect(Collectors.toList());
}

1.2、Optional.of():

例如,在Repository层中,在保存用户和角色关系的方法传入参数userRoleInfo(包含用户id,以及角色)用来保存一个用户的角色信息时所以我们可以使用Optional.of()方法去包装这个userRoleInfo,方便后续的流式操作。在此处就认为userRoleInfo绝对不为null,因为都已经在Repository层了,前面某层应当已经有了校验,这个参数就应当不为null。要注意快速失败原则,及早定位问题。

代码:

java 复制代码
public void saveUserRoleInfo(UserRoleInfo userRoleInfo) {
    Optional.of(userRoleInfo)
            .map(UserRoleInfo::getRoles)
            .ifPresent(roles -> {
                // 保存逻辑
            });
}

3、flatMap():

flatMap主要解决Optional嵌套的问题,例如:Optional<Optional<T>>,在使用Optional的流式编程过程中使用map操作可能会发生Optional的嵌套,而flatMap则会去掉多余的嵌套,只保留原始的Optional包装。与map操作相比,flatMap操作直接返回操作结果,而map操作则在返回结果前使用Optional进行一次包装。比如以下是更新用户地址的一段逻辑,先根据userId查询用户原有的地址,当地址不一样时进行更新。

代码:

java 复制代码
public void updateAddress(AddressInfo addressInfo) {
    Optional.of(addressInfo)
            .map(AddressInfo::getUserId)
            .flatMap(this::getAddressByUser)// getAddressByUser方法返回的对象是Optional的
            .filter()//省略比较逻辑
            .ifPresent(address -> {
                // 省略更新逻辑
            });
}

map操作与flatMap操作源码对比:

map:

flatMap:

4、总结:

Optional的出现与使用,极大的降低了发生空指针的概率,让程序的健壮性提升了不少,对刚接触Optional时时不易理解的部分在实践中也有了一番新的的认识。继续严格要求自己,争取码出一手优雅的代码。

相关推荐
动亦定26 分钟前
页面导出大量数据导致响应超时解决方案
java·mysql
q***06291 小时前
解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务(Spring MVC Springboot)同时允许跨域
java·前端·spring
还是鼠鼠1 小时前
Redisson实现的分布式锁能解决主从一致性的问题吗?
java·数据库·redis·分布式·缓存·面试·redisson
d***95621 小时前
windows配置永久路由
java
王桑.2 小时前
IO流高级流--转换流
java
qq_12498707532 小时前
基于SpringBoot技术的企业请假审批管理系统的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·信息可视化·毕业设计
BBB努力学习程序设计3 小时前
Java方法详解:提升代码复用性与可读性的利器
java
BBB努力学习程序设计3 小时前
Java运算符完全指南:让代码学会“计算”和“判断”
java
用户84913717547163 小时前
ThreadLocal 源码深度解析:JDK 设计者的“妥协”与“智慧”
java·后端
用户0304805912633 小时前
# 【Maven避坑】源码去哪了?一文看懂 Maven 工程与打包后的目录映射关系
java·后端