改进可能产生 NullPointerException 警告的 Intellij 代码检查
Improve Intellij Code Inspection for may produce NullPointerException warnings
我有一个 class 和一个 hasField
函数来检查字段是否存在且不为空,还有一个 getField
函数 return 的值字段(如果不存在则为 null)。
在我检查 hasField
后立即调用 getField
的代码中,我知道 getField 不会 return null,但是 IDE Inspection (常量条件和例外) 不知道。我得到一堆方法 method name
可能会产生一个 NullPointerException
我正在尝试找到一种干净的方法来消除此警告。
解决方法
这里有一些我可以做的变通方法,但我发现所有这些都很麻烦:
- 用
Objects.requireNotnull
包围getField
,代码将是空操作。宁愿不这样做,因为它会使代码的可读性稍差。
- 在我知道这是安全的地方抑制警告。再次不受欢迎,因为这将在我们的代码中的很多地方发生。
- 忽略警告。在这种情况下,我们可能会错过合法的警告,因为警告部分太吵了。
理想解
我能否以某种方式设置警告,如果 hasField
为真,那么 getField
将 return 为非空值?我调查了 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; }
}
我收到以下警告
Method invocation equals
may produce NullPointerException
理想情况下,我希望能够告诉 IDE 当 hasSample 为真时 getSample 不为空。
披露我是负责此子系统的 IntelliJ IDEA 开发人员
不,现在不可能。假设您无法更改 API,没有比您已经列出的可能解决方法更好的解决方案了。我们所拥有的最接近的东西是非常琐碎的方法的内联。但是,它仅在以下情况下有效:
- 像
hasSample()
和 getSample()
这样的方法是从同一个 class 调用的
- 调用的方法不能被覆盖(private/static/final/declared in final class)
例如此功能适用于以下代码:
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); }
}
我有一个 class 和一个 hasField
函数来检查字段是否存在且不为空,还有一个 getField
函数 return 的值字段(如果不存在则为 null)。
在我检查 hasField
后立即调用 getField
的代码中,我知道 getField 不会 return null,但是 IDE Inspection (常量条件和例外) 不知道。我得到一堆方法 method name
可能会产生一个 NullPointerException
我正在尝试找到一种干净的方法来消除此警告。
解决方法
这里有一些我可以做的变通方法,但我发现所有这些都很麻烦:
- 用
Objects.requireNotnull
包围getField
,代码将是空操作。宁愿不这样做,因为它会使代码的可读性稍差。 - 在我知道这是安全的地方抑制警告。再次不受欢迎,因为这将在我们的代码中的很多地方发生。
- 忽略警告。在这种情况下,我们可能会错过合法的警告,因为警告部分太吵了。
理想解
我能否以某种方式设置警告,如果 hasField
为真,那么 getField
将 return 为非空值?我调查了 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; }
}
我收到以下警告
Method invocation
equals
may produceNullPointerException
理想情况下,我希望能够告诉 IDE 当 hasSample 为真时 getSample 不为空。
披露我是负责此子系统的 IntelliJ IDEA 开发人员
不,现在不可能。假设您无法更改 API,没有比您已经列出的可能解决方法更好的解决方案了。我们所拥有的最接近的东西是非常琐碎的方法的内联。但是,它仅在以下情况下有效:
- 像
hasSample()
和getSample()
这样的方法是从同一个 class 调用的
- 调用的方法不能被覆盖(private/static/final/declared in final class)
例如此功能适用于以下代码:
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); }
}