“条件总是假的”来自编译器的警告,条件实际上可能为真

问题描述

我有一个带有这样方法的接口:

public interface MyInterface {
    void myMethod(@Nonnull String userEmail);
}

该接口具有以下实现:

public class MyInterfaceImpl implements MyInterface {
    @Override
    public void myMethod(@Nonnull String userEmail) {
        if ((userEmail== null) || !userEmail.endsWith("something")) {
            throw new SomeException("...");
        }
        ...
    }
}

编译器向我发出警告,说 Condition 'userEmail == null' is always 'false',但这看起来不对。

就我的理解,如果有人使用 javax.annotation.Nonnull调用我的方法,注释 null 会警告编译器,但如果有人向它传递空值,则不会阻止代码编译.所以是的,我的代码可以在某个时候使用 null调用

Compiler warning


Debugging with a null value

请注意,如果我使用选项 -Xlint:all 在命令行上编译,我会收到相同的警告(因此它看起来不像是我的 IDE 中的错误)。

有谁知道我怎样才能摆脱这个警告以及它为什么会发生?

免责声明:我展示的示例只是一个示例,实际代码在达到该条件之前会做一些事情,但没有什么可以使 userEmail == null 始终 false(正如调试器所证明的那样)我附上截图)。

解决方法

正如很多人在评论中提到的那样。它的行为符合预期。 https://checkerframework.org/manual/#nullness-checker 的解释清楚地说明了这里发生的事情:

检查器在这些情况下会发出警告: 当@NonNull 类型的表达式可能变为空值时,因为这是对该类型的误用:空值可能会流向检查器未警告的取消引用。

上述警告仅在您将 -Alint=redundantNullComparison 传递给编译器时才会出现,并且默认情况下处于关闭状态。当您使用 -Xlint:all 进行编译时,即使启用了此警告。

如果您不想在 itellij 上看到此警告,您可以更新您的设置:

设置 (Ctrl+Alt+S / ) > 编辑器 > 检查 > Java > 声明冗余> 使用明显非空参数调用空检查方法。

设置 (Ctrl+Alt+S / ) > 构建、执行、部署 > 编译器 >为非空注释方法和参数添加运行时断言

设置 (Ctrl+Alt+S / ) > 编辑器 > 检查 > Java > 可能的错误

此外,如果您期望空值,那么首先使用该注释似乎是不正确的。

,

您在方法参数上有注释。 @Nonnull String userEmail

因此它预计 userEmail== null 将始终评估为 false,因此没有理由在那里进行检查。

检查关于属于 JSR 305 的 @Nonnullfollowing answer

305 是关于新的注释,你已经可以把它们放在那里,这 可以帮助通过合同提供对设计的程序化可见性 系统。因此,如果某个方法不应该返回 null,或者 如果某个方法应该永远不会收到空参数

因此,如果您作为程序员有信心将该参数注释为 nonNull,那么它为什么不报告检查 userEmail == null 没有意义?使用注解就像你告诉编译器你有信心它永远不会被 null 调用。

注解 @Nonnull 就像描述一个合同。您不会签订明知可能会被破坏的合同。如果您不确定,请删除注释。如果您确定,则取消勾选 userEmail == null