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时时不易理解的部分在实践中也有了一番新的的认识。继续严格要求自己,争取码出一手优雅的代码。

相关推荐
それども4 小时前
Spring Bean 的name可以相同吗
java·后端·spring
墨雪不会编程4 小时前
C++ string 详解:STL 字符串容器的使用技巧
java·开发语言·c++
Lucky GGBond4 小时前
实践开发:老系统新增字段我是如何用枚举优雅兼容历史数据的
java
悲喜自渡7214 小时前
Python 编程(gem5 )
java·linux·开发语言
xing-xing4 小时前
JVM 内存、直接内存、系统内存、本地内存、物理内存总结
java·jvm
yangpipi-4 小时前
《C++并发编程实战》第5章 C++内存模型和原子操作
android·java·c++
qq_12498707535 小时前
基于微信小程序的电子元器件商城(源码+论文+部署+安装)
java·spring boot·spring·微信小程序·小程序·毕业设计
吃喝不愁霸王餐APP开发者5 小时前
基于Spring Cloud Gateway实现对外卖API请求的统一鉴权与流量染色
java·开发语言
a努力。6 小时前
美团Java面试被问:Redis集群模式的工作原理
java·redis·后端·面试
一雨方知深秋6 小时前
面向对象编程
java·封装·this·构造器·static关键字·成员变量·javabean实体类