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

被折叠的 条评论
为什么被折叠?



