Sonar报调用方法返回值未做空校验可能引发空指针解引用如何修复
告警触发原因
Sonar抛出该告警的核心原因有两个:
- 你先调用
templateMessage.getText()做非空校验,后续第二次调用该方法取值传入String.format时,Sonar无法保证两次调用返回值完全一致(比如多线程场景下其他线程修改了templateMessage的text属性),存在第二次调用返回null的风险 System.getProperty("env")方法返回值可能为null,你直接将其传入String.format没有做非空校验,属于未检查方法返回值的场景
修复方案
方案1:本地变量缓存方法返回值(最推荐,改动最小)
把需要多次使用的方法返回值提前用本地变量存储,仅做一次调用+一次非空校验,从根源避免多次调用返回值不一致的问题,同时补全所有可能为null的返回值的默认值处理。
修复后代码如下:
private void sendMail(String msg) { SimpleMailMessage message = null; try { SimpleMailMessage templateMessage = mailSender.getSimpleMailMessage(); if(templateMessage != null ) { message = new SimpleMailMessage(templateMessage); if(message != null) { // 缓存主题模板、环境变量,避免重复调用方法 String subjectTemplate = templateMessage.getSubject(); String env = System.getProperty("env"); // 给环境变量加默认值,避免null传入格式化方法 env = env == null ? "unknown" : env; if(subjectTemplate != null) { message.setSubject(String.format(subjectTemplate, env)); } // 缓存正文模板,只调用一次getText()方法 String textTemplate = templateMessage.getText(); if(textTemplate != null) { // 可选:给入参msg加默认值,避免上层传入null导致格式化异常 String mailContent = msg == null ? "" : msg; message.setText(String.format(textTemplate, mailContent)); } } } } catch (Exception e) { // 建议补充异常捕获逻辑,邮件发送属于非核心流程,失败不要影响主业务运行 // 可自行添加日志打印错误信息 } }
方案2:使用Optional简化非空判断(JDK8及以上版本适用)
如果项目JDK版本在8及以上,可以用Optional类简化非空校验和默认值赋值逻辑,代码更简洁:
// 正文相关逻辑示例 String textTemplate = Optional.ofNullable(templateMessage.getText()).orElse("系统通知"); String env = Optional.ofNullable(System.getProperty("env")).orElse("unknown"); String mailContent = Optional.ofNullable(msg).orElse(""); message.setText(String.format(textTemplate, mailContent));
方案3:注解屏蔽告警(仅临时规避使用,不推荐)
如果经过代码走查确认当前逻辑完全不存在空指针风险,可以在方法上添加对应规则的@SuppressWarnings注解直接屏蔽告警,比如@SuppressWarnings("ConstantConditions"),但该方案会隐藏潜在风险,不建议长期使用。
补充建议
- 如果
SimpleMailMessage类的getSubject()、getText()方法本身确定不会返回null,可以给这两个方法添加@Nonnull注解,Sonar识别后也会自动消除该告警 - 建议补充邮件发送的异常捕获逻辑,避免邮件服务不可用时拖垮主业务流程
内容的提问来源于stack exchange,提问作者Arijit
相关产品推荐
相关产品推荐

