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

相关推荐
书源丶2 小时前
二十八、API之《System 类》——与系统交互的“桥梁”
java·交互
Pluchon2 小时前
硅基计划4.0 算法 字符串
java·数据结构·学习·算法
野生技术架构师2 小时前
1000 道 Java 架构师岗面试题
java·开发语言
青柠编程2 小时前
基于Spring Boot的选课管理系统架构设计
java·spring boot·后端
Mr.wangh2 小时前
Redis主从复制
java·数据库·redis
Porunarufu2 小时前
JAVA·顺序逻辑控制
java·开发语言
1710orange3 小时前
java设计模式:适配器模式
java·设计模式·适配器模式
RainbowSea3 小时前
9. Spring AI 当中对应 MCP 的操作
java·spring·ai编程
RainbowSea4 小时前
10. Spring AI + RAG
java·spring·ai编程
寻星探路4 小时前
Java EE初阶启程记05---线程安全
java·开发语言·java-ee