相等检查后使用 Long 的 NullPointerException

Rob*_*len 5 java casting nullpointerexception long-integer

这让我很震惊。

如果您有一个 Java Long 变量,并且使用 == 运算符检查与原始值的相等性,则该值的运行时类型将更改为原始 long。

随后检查变量是否为空值,然后抛出意外的 NullPointerException。

所以在测试类中:

public class LongDebug {

public static void main(String[] args) {
    Long validValue = 1L; 
    Long invalidValue = -1L;
    Long nullValue = null;

    System.out.println("\nTesting the valid value:");
    testExpectedBehaviour(validValue);
    testUnExpectedBehaviour(validValue);

    System.out.println("\nTesting the invalid value:");
    testExpectedBehaviour(invalidValue);
    testUnExpectedBehaviour(invalidValue);

    System.out.println("\nTesting the null value:");
    testExpectedBehaviour(nullValue);
    testUnExpectedBehaviour(nullValue);
}

/**
 * @param validValue
 */
private static void testExpectedBehaviour(Long value) {
    if (value == null || value == -1) System.out.println("Expected: The value was null or invalid");
    else System.out.println("Expected: The value was valid");
}

private static void testUnExpectedBehaviour(Long value) {
    try {
        if (value == -1 || value == null) System.out.println("Unexpected: The value was null or invalid");
        else System.out.println("Unexpected: The value was valid");
    } catch (NullPointerException e) {
        System.out.println("Unexpected: The system threw an unexpected NullPointerException");
    }
}
}
Run Code Online (Sandbox Code Playgroud)

我得到的结果是:

Testing the valid value:
Expected: The value was valid
Unexpected: The value was valid

Testing the invalid value:
Expected: The value was null or invalid
Unexpected: The value was null or invalid

Testing the null value:
Expected: The value was null or invalid
Unexpected: The system threw an unexpected NullPointerException
Run Code Online (Sandbox Code Playgroud)

这是符合规范的还是 JDK 中的错误?

Tom*_*icz 4

这就是问题:

value == -1 || value == null
Run Code Online (Sandbox Code Playgroud)

表达式从左到右计算,并且由于Long必须首先拆箱,JVM 将其转换为:

value.longValue() == -1 || value == null
Run Code Online (Sandbox Code Playgroud)

并在争论时value.longValue()抛出。它永远不会到达表达式的第二部分。NullPointerExceptionvaluenull

当顺序不同时它会起作用:

value == null || value == -1
Run Code Online (Sandbox Code Playgroud)

因为如果valueis ,则由于布尔表达式短路求值,第二null部分(可能导致NullPointerExceptionis )永远不会执行。valuenull

这是符合规范的还是 JDK 中的错误?

当然这不是一个错误。原始值包装器拆箱的方式符合规范(5.1.8.拆箱转换):

  • 如果r是类型的引用Long,则拆箱转换将转换rr.longValue()

应用拆箱后,剩下的就是标准的Java。