改进Intellij代码检查,可能会产生NullPointerException警告

时间:2020-03-03 00:13:38

标签: java intellij-idea annotations code-inspection

我有一个带有hasField函数的类,该函数检查某个字段是否存在并且不为空,而一个getField函数则返回该字段的值(如果不存在,则为null)。 / p>

在我的代码中,当我在检查getField之后立即调用hasField时,我知道getField不会返回null,而是IDE检查(恒定条件和异常 )不知道。我得到了一堆方法method name可能会产生一个NullPointerException

我正在尝试寻找一种清除此警告的干净方法。

解决方法

以下是我可以做的一些解决方法,但我发现所有这些技巧都很简单:

  1. getFieldObjects.requireNotnull环绕在一起,代码将变为空操作。最好不要这样做,因为这会使代码的可读性稍差。
  2. 在我知道这是安全的地方禁止警告。再次也不是首选,因为这将在代码中的很多地方发生。
  3. 忽略警告。在这种情况下,我们可能会因为警告部分太吵而错过合法警告。

理想的解决方案

我能够以某种方式设置警告,如果hasField为true,那么getField将返回非null吗?我调查了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

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

1 个答案:

答案 0 :(得分:2)

公开信息我是负责此子系统的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); }
}