java - 改进 Intellij 代码检查以防止可能产生 NullPointerException 警告
问题描述
我有一个类,它带有一个hasField
检查字段是否存在且不为 null 的getField
函数,以及一个返回字段值的函数(如果不存在,则返回 null)。
在我的代码中,当我getField
在检查后立即调用时hasField
,我知道 getField 不会返回 null,但 IDE 检查(常量条件和异常)不知道这一点。我得到一堆方法method name
可能会产生一个NullPointerException
我正在尝试找到一种干净的方法来消除此警告。
解决方法
以下是我可以做的一些变通办法,但我发现所有这些都很奇怪:
- 包围
getField
,Objects.requireNotnull
代码将是无操作的。宁愿不这样做,因为它会使代码的可读性稍差。 - 在我知道这是安全的地方禁止警告。同样不是首选,因为这将发生在我们代码中的很多地方。
- 忽略警告。在这种情况下,我们可能会因为警告部分太吵而错过合法警告。
理想的解决方案
我是否能够以某种方式设置警告,如果hasField
为真,那么getField
将返回非空值?我查看了JetBrains Contract Annotations但在这里做我想做的似乎超出了@Contract 所支持的范围
代码示例
这是演示该问题的最低工作代码示例:
import javax.annotation.Nullable;
public class Hello {
private Hello(){}
public static void main(String[] args) {
TestClass test1 = new TestClass(null);
if (test1.hasSample()) {
System.out.println(test1.getSample().equals("abc"));
}
}
}
class TestClass {
private final String sample;
TestClass(String field) { this.sample = field; }
boolean hasSample() { return sample != null; }
@Nullable public String getSample() { return sample; }
}
我收到以下警告
方法调用
equals
可能产生NullPointerException
理想情况下,当 hasSample 为真时,我希望能够告诉 IDE getSample 不为空。
解决方案
披露我是负责这个子系统的 IntelliJ IDEA 开发人员
不,现在不可能。假设您无法更改 API,没有比您已经列出的可能解决方法更好的解决方案了。我们拥有的最接近的东西是非常琐碎的方法的内联。但是,它仅在以下情况下有效:
hasSample()
类似和的方法getSample()
是从同一个类中调用的- 被调用的方法不能被覆盖(私有/静态/最终/在最终类中声明)
例如,此功能在以下代码中起作用:
final class TestClass { // if final is removed, the warning will appear again
private final String sample;
TestClass(String field) { this.sample = field; }
boolean hasSample() { return sample != null; }
@Nullable
public String getSample() { return sample; }
@Override
public String toString() {
if (hasSample()) {
return "TestClass: "+getSample().trim(); // no warning on trim() invocation here
}
return "TestClass";
}
}
目前,我只能建议将您的 API 重构为 Optionals,如下所示:
import java.util.Optional;
public class Hello {
private Hello(){}
public static void main(String[] args) {
TestClass test1 = new TestClass(null);
test1.getSample().ifPresent(s -> System.out.println(s.equals("abc")));
// or fancier: test1.getSample().map("abc"::equals).ifPresent(System.out::println);
}
}
final class TestClass {
private final String sample;
TestClass(String field) { this.sample = field; }
public Optional<String> getSample() { return Optional.ofNullable(sample); }
}
推荐阅读
- performance-testing - 获取响应正文中的值,但 web_reg_save_param 未捕获某些请求
- xslt - eXist DB 和 Xquery:xincludes 还是集合 (TEI-XML)?
- php - 控制器中的 if else 语句在 Laravel 中没有响应
- php - LimitIterator 偏移量 1 和 2 个元素
- mongodb - Mongodb 指南针和 Phpmyamin 的相似之处
- javascript - 如何在 reactjs 中手动重新编译 LESS?
- soundcloud - Soundcloud trackID by track URL 地址
- android - Firebase 迭代很慢
- c# - 如何在不使用 C# 覆盖的情况下附加到现有 Excel 文件?
- c++ - 从 vscode 开始