【问题标题】:Google-guava checkNotNull and IntelliJ IDEA's "may produce java.lang.NullPointerException"Google-guava checkNotNull 和 IntelliJ IDEA 的“可能会产生 java.lang.NullPointerException”
【发布时间】:2011-09-29 16:56:11
【问题描述】:

有没有办法抑制这个警告:

MyClass object = null;

/*Some code that 'might' set this object but I know it will*/      


Preconditions.checkNotNull(object); 
//when "assert object != null" is used here no warning is shown

merged.setName(dRElement.getName());
//"May produce 'java.lang.NullPointerException'" warning here 

我正在使用 IntelliJ IDEA 10.5,我知道这个警告是不必要的,但是我想在这里取消它并避免关闭检查。

【问题讨论】:

  • 你的意思是对象而不是合并?
  • 我的意思是 object 而不是 'dRElement' 但在这个例子中是一样的。
  • 也有兴趣。每次我必须通过重复断言/抑制来解决此警告时,我都会感到沮丧。

标签: intellij-idea nullpointerexception guava inspection


【解决方案1】:

通过@Contract 注释和外部注释功能的组合,您现在可以注释Preconditions 方法,以便 IntelliJ 对这些方法的调用应用正确的静态分析。

假设我们有这个例子

public void doSomething(Object someArg) {
    Preconditions.checkArgument(someArg != null);
    someArg.doSomethingElse();  //currently gives NPE warning

    if (someArg != null) {
        //no warning that this is always true
    }
}

在 IntelliJ 中(我使用的是 13):

  • 导航到Preconditions.checkArgument(boolean)
  • 将光标放在方法名称上,然后按 Alt-Enter 以弹出意图弹出窗口。
  • 选择“添加方法合同”。
  • 使用合同文本false -> fail
  • 出现提示时,提供外部注释文件的位置。

现在someArg.doSomethingElse() 的警告消失了,IDEA 实际上会将if 分支标记为始终正确!

其他合同文本:

  • Preconditions.checkArgument(boolean, String) 应该是 false, _ -> fail
  • Preconditions.checkNotNull(Object, String) 应该是 null, _ -> fail
  • 等等等等

这是我完整的annotations.xmlPreconditions 文件:

<root>
    <item name='com.google.common.base.Preconditions T checkNotNull(T)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;null -&gt; fail&quot;"/>
        </annotation>
    </item>
    <item name='com.google.common.base.Preconditions T checkNotNull(T, java.lang.Object)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;null, _ -&gt; fail&quot;"/>
        </annotation>
    </item>
    <item name='com.google.common.base.Preconditions T checkNotNull(T, java.lang.String, java.lang.Object...)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;null, _, _ -&gt; fail&quot;"/>
        </annotation>
    </item>
    <item name='com.google.common.base.Preconditions void checkArgument(boolean)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;false -&gt; fail&quot;"/>
        </annotation>
    </item>
    <item name='com.google.common.base.Preconditions void checkArgument(boolean, java.lang.Object)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;false, _ -&gt; fail&quot;"/>
        </annotation>
    </item>
    <item name='com.google.common.base.Preconditions void checkArgument(boolean, java.lang.String, java.lang.Object...)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;false, _, _ -&gt; fail&quot;"/>
        </annotation>
    </item>
    <item name='com.google.common.base.Preconditions void checkState(boolean)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;false -&gt; fail&quot;"/>
        </annotation>
    </item>
    <item name='com.google.common.base.Preconditions void checkState(boolean, java.lang.Object)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;false, _ -&gt; fail&quot;"/>
        </annotation>
    </item>
    <item name='com.google.common.base.Preconditions void checkState(boolean, java.lang.String, java.lang.Object...)'>
        <annotation name='org.jetbrains.annotations.Contract'>
            <val val="&quot;false, _, _ -&gt; fail&quot;"/>
        </annotation>
    </item>
</root>

另见

【讨论】:

  • 为此更改了答案。这正是我想要的!
  • 如何设置 IntelliJ 以实际使用该 annotations.xml 文件?
  • @PeterŠtibraný:IIRC,第一次声明外部注释时,系统会提示您输入创建外部注释文件的位置。然后你就可以把这些内容复制进去了。
【解决方案2】:

old issue exists in JetBrains Yourtrack 添加此类功能。几年前我投票支持它,但我没有看到任何活动。如果每个人都投票支持它,那么我们可能会很幸运。

为了澄清问题,包括添加功能,以便您可以将方法标记为执行某种类型的空值检查。如果发生这种情况,那么您可以为 Preconditions 方法编写自己的包装器并对其进行注释。

更新 我厌倦了等待功能,所以我自己提交了一个补丁。它在 12.1.1 版本 129.239 中可用。要访问配置:设置 > 检查 > 可能的错误 > 常量条件和异常 > 配置断言/检查方法。

【讨论】:

  • 很遗憾我不知道。我从未真正见过一种模式,我认为这与他们实现它的难易程度以及他们对这个想法的喜爱程度有关。
  • 如果有人感兴趣,我刚刚提交了一个补丁,希望能将所需的功能添加到 Intellij。我不知道 JetBrains 需要多长时间来审核更改并将其包含在生产版本中。如果您有时间,请对该问题进行投票/评论,以提高其在 JetBrains 工作人员中的知名度。这是我为 Intellij 提供的第一个补丁,因此审核可能需要很长时间。
  • 非常感谢。您的解决方案比他们现在实施的要好得多。我真的开始后悔更新到 IDEA 13 :-(
  • 这是不是从 Idea 13 中消失了?我记得在以前的版本中设置过,但现在找不到了。
【解决方案3】:

提取方法?

private MyClass getMyClass() {
    /* This always returns an instance of MyClass, never null. */      
}

...

MyClass object = getMyClass();
Preconditions.checkNotNull(object);
merged.setName(object.getName());

【讨论】:

    【解决方案4】:

    您也可以从 checkNotNull 方法中分配返回值,它是非空的:http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/Preconditions.html#checkNotNull(T)

    MyClass object = null;
    object = Preconditions.checkNotNull(object); 
    merged.setName(dRElement.getName());
    

    【讨论】:

      【解决方案5】:

      从 IntelliJ IDEA 14 开始,您无需担心这一点。

      @Nullable
      String extractPrefix(@Nullable String url) {
          if (StringUtils.isEmpty(url)) return null;
      
          if (url.startsWith("jar://")) {
      ...
      

      早期的 IntelliJ IDEA 不知道如果 url 为空,代码执行甚至不会到达“startsWith”调用,因为它没有查看 StringUtils.isEmpty 内部。您当然可以通过自己查看 isEmpty 并添加合同“null -> true”来删除 extractPrefix 中的那些黄色警告,但这太无聊了!这完全是计算机的工作,而不是你,现在 IntelliJ IDEA 会自动完成,查看字节和源代码。

      http://blog.jetbrains.com/idea/2014/10/automatic-notnullnullablecontract-inference-in-intellij-idea-14/

      【讨论】:

        【解决方案6】:

        除了其他选项,你可以试试-

        使用 -

        在方法级别抑制警告
        @SuppressWarnings({"NullableProblems"})
        public void someMethod(){
           ...
           ...
        }
        

        或使用注释在语句级别禁止警告 -

        //noinspection NullableProblems
        someMethodCallProducingNullWarning(null);
        

        但在此之前 - 确保它不会真正产生 NPE

        【讨论】:

        • 这些是默认选项。您可以将assert var != nullPreconditions.checkNotNull 一起使用,但就像//noinspection 一样是多余的。
        • 这里是代码link,由于复制粘贴,标签有点乱
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-08
        • 1970-01-01
        • 1970-01-01
        • 2015-06-29
        • 1970-01-01
        相关资源
        最近更新 更多