Java &引用;“条件总是错误的”;编译器发出的警告,条件可能为真

Java &引用;“条件总是错误的”;编译器发出的警告,条件可能为真,java,compiler-warnings,Java,Compiler Warnings,我有这样一个方法的接口: public interface MyInterface { void myMethod(@Nonnull String userEmail); } 该接口具有以下实现: public class MyInterfaceImpl implements MyInterface { @Override public void myMethod(@Nonnull String userEmail) { if ((userEmail==

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

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("...");
        }
        ...
    }
}
编译器向我发出警告说,
条件“userEmail==null”总是“false”
,但这看起来不对

据我所知,注释
javax.annotation.Nonnull
将在有人使用
null
值调用我的方法时警告编译器,但如果有人向其传递null值,则不会阻止代码编译。因此,是的,我的代码可以在某个点用
null
值调用:


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

有人知道我怎样才能摆脱这个警告吗?为什么会这样


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

您在方法参数上有注释
@非空字符串userEmail

因此,它期望
userEmail==null
的计算结果总是为false,因此没有理由出现在if检查中

检查有关属于JSR 305的
@Nonnull

305是关于新的注释,您可以在其中放置它们,这 可以帮助提供合同设计的程序可视性 系统。如果某个方法不应该返回null,或者 如果某个方法被认为永远不会接收空参数

因此,如果作为程序员,您有信心将该参数注释为非null,为什么它不报告check
userEmail==null
没有任何意义?使用注释就像通知编译器您有信心永远不会使用null调用它


注释
@Nonnull
类似于描述合同。你不会签订你知道会被破坏的合同。如果不确定,请删除注释。如果确定,请删除复选框
userEmail==null

,因为评论中已经提到了很多人。它的行为符合预期。来自的解释清楚地说明了这里发生了什么:

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

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

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

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

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

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


另外,如果您期望一个空值,那么首先使用该注释似乎是不对的。

@ruakh Java version:11.0.2-BellSoft,vendor:BellSoft,runtime:C:\jdk-11.0.2哪个
@Nonnull
是这样的注释?我认为源代码级别的注释是这样的(比如lombok给出的注释)实际上,生成一个检查代码中是否有null的
if
块。如果是这种情况,那么编译器是正确的。您可能需要对类文件进行反编译,以查看最终的代码。@ernest_k:Lombok的注释处理器仅对Lombok自己的@NonNull执行此操作。
javax.annotation.NonNull
(OP正在使用的)没有这种行为。@Nonnull不会按照您的想法执行。它会告诉编译器它应用的参数不能为null。因此您的
==null
测试不能为真。因为如前所述,您打开了linter。这将保证正确性,并使
if
冗余。非常感谢您花时间编写答案。正如我在问题主体和评论中所述,我使用的是
javax.annotations.Nonnull
,而不是
org.checkerframework.checker.nullness.qual.Nonnull
,这正是您在回答中提到的值。此外,我不期望
null
值(这就是为什么我用
@Nonnull
进行注释,以便我的服务的客户端在传递
null
时会看到编译器警告),但我不能确定是否有人会发送它,如果是这样,我想发送一个明确的异常,说明我为什么不接受他们的请求(这就是我在代码中检查
null
的原因)。@MatteoNNZ此注释仅用于linting和警告。如果要引发异常,可以使用lambok的notNull或Objects。requirennull(object);我的输入字符串需要验证,我需要调用endsWith()因此,如果使用空字符串调用我,我将面临空指针异常的风险。我希望捕获空字符串/无效字符串,并发送一个特定的异常,而不仅仅是NPE,这就是为什么我首先使用if null条件编写代码的原因。无论如何,似乎没有人能像我一样看到它:)看起来我是唯一一个看到这种情况的人,但我真的没有得到一点。将参数注释为@Nonnull将使编译器警告任何使用null值调用我的方法的人,他们正在将null传递到一个不需要null的方法中。这很好。但它实际上并不阻止任何人发送null值。