【问题标题】:Improve Intellij Code Inspection for may produce NullPointerException warnings改进 Intellij 代码检查以防止可能产生 NullPointerException 警告
【发布时间】:2020-03-03 00:13:38
【问题描述】:

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

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

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

解决方法

这里有一些我可以做的变通办法,但我发现所有这些都很奇怪:

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

理想的解决方案

我能否以某种方式设置警告,如果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 为 true 时告诉 IDE getSample 不为空。

【问题讨论】:

    标签: java intellij-idea annotations code-inspection


    【解决方案1】:

    披露我是负责这个子系统的 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 重构为 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); }
    }
    

    【讨论】:

    • 感谢您的快速回复。现在我决定忽略这些警告。
    猜你喜欢
    • 2018-08-24
    • 2014-04-21
    • 1970-01-01
    • 2017-06-26
    • 2016-09-13
    • 2018-12-27
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多