java - 改进 Intellij 代码检查,以防止可能产生 NullPointerException 警告

标签 java intellij-idea annotations code-inspection

我有一个带有 hasField 函数的类,用于检查字段是否存在且不为空,以及一个 getField 函数,用于返回字段的值(或 null如果不存在)。

在我的代码中,当我在检查 hasField 后立即调用 getField 时,我知道 getField 不会返回 null,但 IDE 检查(恒定条件和异常)不知道这一点。我得到一堆方法方法名称可能会产生NullPointerException

我正在尝试找到一种干净的方法来消除此警告。

解决方法

这里有一些我可以做的解决方法,但我发现所有这些都很棘手:

  1. Objects.requireNotnull 包围 getField,代码将是无操作的。我宁愿不这样做,因为它会使代码的可读性稍差。
  2. 在我知道这是安全的情况下禁止显示警告。同样不是首选,因为这会发生在我们代码中的很多地方。
  3. 忽略警告。在这种情况下,我们可能会错过合法的警告,因为警告部分的噪音太大。

理想的解决方案

我是否能够以某种方式设置警告,如果 hasField 为 true,则 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; }
}

我收到以下警告

Method invocation equals may produce NullPointerException

理想情况下,我希望能够在 hasSample 为 true 时告诉 IDE getSample 不为 null。

最佳答案

披露我是负责此子系统的 IntelliJ IDEA 开发人员


不,现在不可能。假设您无法更改 API,没有比您已经列出的可能解决方法更好的解决方案了。我们拥有的最接近的东西是非常简单的方法的内联。但是,它仅在以下情况下有效:

  • hasSample()getSample() 等方法是从同一个类调用的
  • 被调用的方法不能被重写(private/static/final/final类中声明的)

例如此功能在以下代码中起作用:

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 重构为可选的,如下所示:

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); }
}

关于java - 改进 Intellij 代码检查,以防止可能产生 NullPointerException 警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60498381/

相关文章:

java - 使用 ThreadLocalTargetSource 填充的 Autowiring 对象不会为每个类填充

java - IntelliJ IDEA 社区 + Java 11

intellij-idea - 如何在ideavim中进行不区分大小写的搜索(使用/和?)

annotations - 如何在 Google Charts 中设置注释线的样式?

java - Java中的注解处理是什么?

java - 频谱图的频率范围

java - JTable.print() 不打印所有列

intellij-idea - 如何替换路径中的多行文本?

iphone - MKMapView -> 为我的位置显示一个按钮

java - ProgressBar 在 AsyncTask 期间不显示