sonar 检测 Call “Optional#isPresent()“ before accessing the value.(java 8 版本)

本文介绍了如何在Java8中正确使用Optional以避免NPE,尤其是在Stream操作中。讨论了两种修正策略:一是中断链式调用进行空检查,二是利用orElseGet实现默认值。还提到针对特定场景的优化,如仅处理属性值并使用mapToLong。

问题代码

public class demoUtil {
	public static Long methdName(List<EnterpriseSolutionsSeq> seqList){
		if(CollUtil.isEmpty(seqList)){
			return null;
		}
		// 下面这行代码会被sonar检测有问题,因为在对Optional对象使用get前没有使用 isPresent()进行校验
		// Optional对象来源因为用了Stream 的 min 方法,其返回值是 Optional类型的
		EnterpriseSolutionsSeq solutionsSeq = seqList.stream().filter(Objects::nonNull).min(Comparator.comparing(EnterpriseSolutionsSeq::getSeq)).get();
		return solutionsSeq.getSeq();
	}
}

解决问题的背景知识

java8 Optional 的使用规范要求的规则。

推荐阅读:理解、学习与使用 Java 中的 Optional

个人读后感:Optional 是为了解决 java 经常遇到的 NullPointerException(简称NPE) 异常而引入的新的类。Optional只是一个语法糖,就算使用了 Optional 但如果不规范使用还是会有NPE出现。感觉有两点作用,一点是当编码时遇到传过来的是Optional类型时,警醒开发人员需要关注NPE风险(这点对于sonar等代码检测工具有很大的帮助);另外一点价值更大的就是对于链式调用和lambda的使用方式时,对于判定对象是否为null,安排后续处理逻辑,可以链式到底(java9也完善了下Optional的链式方法)。

Optional 使用规范使用get方法(获取对象)前要先使用 isPresent() 来判定Optiona包含的对象是否为空。

对于这点跟使用普通的 if else 判定对象是否为 null没有什么区别,只不过语法检测工具可以根据当前是Optional对象来更好的明确提醒你判定是否为null

推荐阅读:Optional用法(Java SE 8–Java SE 9)

Java 8 Stream

推荐阅读:Java 8 Stream

本次问题产生原因就是 Stream 一些方法会返回 Optional 类型数据,直接使用get()导致的。

修改策略

java8

方法1

中断了链式编程,拿出min处理后的 Optional 结果 来if isPresent() 判定下,这是本人最开始百度找到的解决sonar报错的简单粗暴解决方案,不推荐。

public class demoUtil {

	public static Long methdName(List<EnterpriseSolutionsSeq> seqList){
		if(CollUtil.isEmpty(seqList)){
			return null;
		}
		
		Optional<EnterpriseToolsSeq> min = toolsSeqList.stream().filter(Objects::nonNull).min(Comparator.comparing(EnterpriseToolsSeq::getSeq));
		if(min.isPresent()){
			return min.get().getSeq();
		}
		return 1000000L;
	}
}
方式2

使用orElseGet 或者 orElse。

推荐阅读:Java8之Optional中orElse和orElseGet的区别

推荐使用 orElseGet(null时候被调用的方法,一般是封装一个会返回默认值的对象方法),除非Null时返回的对象已经存在创建好,否则不推荐使用orElse(null时返回的默认对象或方法执行后返回的默认对象)。
orElseGet该方法逻辑是,判定对象如果不是null 则直接返回该对象,如果是null则调用OrElseGet后面括号里的方法,一般是组装一个默认对象并返回的方法。
OrElse该方法逻辑是,判定对象如果不是null 则直接返回该对象,如果是null则触发返回OrElse后面括号里的默认对象,或者是能返回对象的方法。
没有使用方便的 orElse 是因为对性能影响风险小,本例来说orElse 和orElseGet性能影响不大。

参考阅读:Java 9 改进的 Optional 类添加了三个方法来改进它的功能:stream(),ifPresentOrElse(),or()

public class demoUtil {

	public static Long methdName(List<EnterpriseSolutionsSeq> seqList){
		if(CollUtil.isEmpty(seqList)){
			return null;
		}
		EnterpriseSolutionsSeq solutionsSeq = seqList.stream().filter(Objects::nonNull).min(Comparator.comparing(EnterpriseSolutionsSeq::getSeq)).orElseGet( () -> {
			EnterpriseSolutionsSeq enterpriseSolutionsSeq = new EnterpriseSolutionsSeq();
			enterpriseSolutionsSeq.setSeq(100000L);
			return  enterpriseSolutionsSeq;
		});
		return solutionsSeq.getSeq();
	}
}

鉴于本次返回只需要比较对象里的一个属性(Long类型),可以在Stream期间只处理改属性的值,用map(本次是MapToLong)方法处理下。再比较大小,以及最后返回默认的10000L

public class demoUtil {

	public static Long methdName(List<EnterpriseSolutionsSeq> seqList){
		if(CollUtil.isEmpty(seqList)){
			return null;
		}
		return toolsSeqList.stream().filter(Objects::nonNull).mapToLong(en->en.getSeq()).min().orElseGet(()->{return 100000L;});
	}
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值