返回 null 作为 int 允许使用三元运算符,但不允许使用 if 语句

发布于 2024-12-15 05:02:19 字数 997 浏览 1 评论 0 原文

让我们看一下以下代码片段中的简单 Java 代码:

public class Main {

    private int temp() {
        return true ? null : 0;
        // No compiler error - the compiler allows a return value of null
        // in a method signature that returns an int.
    }

    private int same() {
        if (true) {
            return null;
            // The same is not possible with if,
            // and causes a compile-time error - incompatible types.
        } else {
            return 0;
        }
    }

    public static void main(String[] args) {
        Main m = new Main();
        System.out.println(m.temp());
        System.out.println(m.same());
    }
}

在这个最简单的 Java 代码中,即使函数的返回类型为 int,temp() 方法也不会发出编译器错误。 code>,并且我们尝试返回值 null(通过语句 return true ? null : 0;)。编译时,这显然会导致运行时异常NullPointerException

然而,如果我们用 if 语句表示三元运算符(如 same() 方法),那么似乎同样的事情是错误的,确实< /em> 发出编译时错误!为什么?

Let's look at the simple Java code in the following snippet:

public class Main {

    private int temp() {
        return true ? null : 0;
        // No compiler error - the compiler allows a return value of null
        // in a method signature that returns an int.
    }

    private int same() {
        if (true) {
            return null;
            // The same is not possible with if,
            // and causes a compile-time error - incompatible types.
        } else {
            return 0;
        }
    }

    public static void main(String[] args) {
        Main m = new Main();
        System.out.println(m.temp());
        System.out.println(m.same());
    }
}

In this simplest of Java code, the temp() method issues no compiler error even though the return type of the function is int, and we are trying to return the value null (through the statement return true ? null : 0;). When compiled, this obviously causes the run time exception NullPointerException.

However, it appears that the same thing is wrong if we represent the ternary operator with an if statement (as in the same() method), which does issue a compile-time error! Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

惜醉颜 2024-12-22 05:02:19

编译器将 null 解释为对 Integer 的 null 引用,对条件运算符应用自动装箱/拆箱规则(如 Java 语言规范,15.25),并且愉快地移动 在。这将在运行时生成一个 NullPointerException ,您可以通过尝试来确认。

The compiler interprets null as a null reference to an Integer, applies the autoboxing/unboxing rules for the conditional operator (as described in the Java Language Specification, 15.25), and moves happily on. This will generate a NullPointerException at run time, which you can confirm by trying it.

内心荒芜 2024-12-22 05:02:19

我认为,Java编译器解释 true ? null : 0 作为 Integer 表达式,可以隐式转换为 int,可能会给出 NullPointerException

对于第二种情况,表达式 null 是特殊的 null 类型 see,因此代码 return null 导致类型不匹配。

I think, the Java compiler interprets true ? null : 0 as an Integer expression, which can be implicitly converted to int, possibly giving NullPointerException.

For the second case, the expression null is of the special null type see, so the code return null makes type mismatch.

烟酉 2024-12-22 05:02:19

实际上,这一切都在 Java 语言规范中进行了解释

条件表达式的类型确定如下:

  • 如果第二个和第三个操作数具有相同的类型(可能是 null 类型),则该类型就是条件表达式的类型。

因此,(true ? null : 0) 中的“null”获取 int 类型,然后自动装箱为 Integer。

尝试类似的方法来验证此 (true ? null : null) ,您将收到编译器错误。

Actually, its all explained in the Java Language Specification.

The type of a conditional expression is determined as follows:

  • If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

Therefore the "null" in your (true ? null : 0) gets an int type and then is autoboxed to Integer.

Try something like this to verify this (true ? null : null) and you will get the compiler error.

倾城花音 2024-12-22 05:02:19

对于 if 语句,null 引用不会被视为 Integer 引用,因为它不参与表达式 这迫使它被这样解释。因此,该错误可以在编译时轻松捕获,因为它更明显是一个类型错误。

至于条件运算符,Java 语言规范第 15.25 节“条件运算符 ? :”在如何应用类型转换的规则中很好地回答了这个问题:

  • 如果第二个和第三个操作数具有相同的类型(可能是 null
    type),那么这就是条件表达式的类型。

    不适用,因为 null 不是 int

<小时>

  • 如果第二个和第三个操作数之一是布尔类型并且
    other 为 Boolean 类型,则条件表达式的类型为 boolean。

    不适用,因为 nullint 都不是 booleanBoolean

<小时>

  • 如果第二个和第三个操作数之一是 null 类型并且是
    other 是引用类型,那么条件表达式的类型是
    引用类型。

    不适用,因为 null 是 null 类型,但 int 不是引用类型。

<小时>

  • 否则,如果第二个和第三个操作数具有可转换的类型
    (§5.1.8) 转换为数字类型,那么有几种情况:[…]

    适用:null 被视为可转换为数字类型,并在第 5.1.8 节“拆箱转换”中定义以引发 NullPointerException

In the case of the if statement, the null reference is not treated as an Integer reference because it is not participating in an expression that forces it to be interpreted as such. Therefore the error can be readily caught at compile-time because it is more clearly a type error.

As for the conditional operator, the Java Language Specification §15.25 “Conditional Operator ? :” answers this nicely in the rules for how type conversion is applied:

  • If the second and third operands have the same type (which may be the null
    type), then that is the type of the conditional expression.

    Does not apply because null is not int.


  • If one of the second and third operands is of type boolean and the type of the
    other is of type Boolean, then the type of the conditional expression is boolean.

    Does not apply because neither null nor int is boolean or Boolean.


  • If one of the second and third operands is of the null type and the type of the
    other is a reference type, then the type of the conditional expression is that
    reference type.

    Does not apply because null is of the null type, but int is not a reference type.


  • Otherwise, if the second and third operands have types that are convertible
    (§5.1.8) to numeric types, then there are several cases: […]

    Applies: null is treated as convertible to a numeric type, and is defined in §5.1.8 “Unboxing Conversion” to throw a NullPointerException.

浅沫记忆 2024-12-22 05:02:19

首先要记住的是,Java 三元运算符有一个“类型”,这是编译器将确定和考虑的内容,无论第二个或第三个参数的实际/真实类型是什么。根据多种因素,三元运算符类型以不同的方式确定,如 Java 语言规范 15.26

在上面的问题中,我们应该考虑最后一种情况:

否则,第二个和第三个操作数的类型分别为 S1S2。令 T1 为将装箱转换应用于 S1 所产生的类型,并令 T2 为将装箱转换应用于 S1 所产生的类型>S2。条件表达式的类型是将捕获转换 (§5.1.10) 应用于 lub(T1, T2) (§15.12.2.7) 的结果。

一旦您查看应用捕获转换 (§5.1.10),最重要的是lub(T1, T2)

用简单的英语并经过极端简化后,我们可以将这个过程描述为计算第二个和第三个参数的“最不常见超类”(是的,想想 LCM)。这将为我们提供三元运算符“类型”。再说一次,我刚才所说的是一种极端的简化(考虑实现多个公共接口的类)。

例如,如果您尝试以下操作:

long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));

您会注意到条件表达式的结果类型是 java.util.Date,因为它是 Timestamp 的“最不常见的超类” >/时间 对。

由于 null 可以自动装箱为任何内容,因此“最不常见的超类”是 Integer 类,这将是上面条件表达式(三元运算符)的返回类型。返回值将是一个 Integer 类型的空指针,这就是三元运算符返回的值。

在运行时,当 Java 虚拟机拆箱 Integer 时,会抛出 NullPointerException。发生这种情况是因为 JVM 尝试调用函数 null.intValue(),其中 null 是自动装箱的结果。

在我看来(因为我的观点不在 Java 语言规范中,所以很多人无论如何都会发现它是错误的)编译器在评估问题中的表达式方面做得很差。鉴于您写了 true ? param1 : param2 编译器应立即确定第一个参数 -null- 将被返回,并且应生成编译器错误。这有点类似于当您编写 while(true){} 等... 时,编译器会抱怨循环下面的代码,并使用 Unreachable statements 对其进行标记。

你的第二种情况非常简单,这个答案已经太长了......;)

更正:

经过另一次分析,我相信我错误地认为 null 值可以被装箱/自动装箱到任何东西。谈论 Integer 类,显式装箱包括调用 new Integer(...) 构造函数或者可能是 Integer.valueOf(int i); (我发现这个版本某处)。前者会抛出 NumberFormatException (这不会发生),而第二个则没有意义,因为 int 不能为 null。 。

The first thing to keep in mind is that Java ternary operators have a "type", and that this is what the compiler will determine and consider no matter what the actual/real types of the second or third parameter are. Depending on several factors the ternary operator type is determined in different ways as illustrated in the Java Language Specification 15.26

In the question above we should consider the last case:

Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).

This is by far the most complex case once you take a look at applying capture conversion (§5.1.10) and most of all at lub(T1, T2).

In plain English and after an extreme simplification we can describe the process as calculating the "Least Common Superclass" (yes, think of the LCM) of the second and third parameters. This will give us the ternary operator "type". Again, what I just said is an extreme simplification (consider classes that implement multiple common interfaces).

For example, if you try the following:

long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));

You'll notice that resulting type of the conditional expression is java.util.Date since it's the "Least Common Superclass" for the Timestamp/Time pair.

Since null can be autoboxed to anything, the "Least Common Superclass" is the Integer class and this will be the return type of the conditional expression (ternary operator) above. The return value will then be a null pointer of type Integer and that is what will be returned by the ternary operator.

At runtime, when the Java Virtual Machine unboxes the Integer a NullPointerException is thrown. This happens because the JVM attempts to invoke the function null.intValue(), where null is the result of autoboxing.

In my opinion (and since my opinion is not in the Java Language Specification many people will find it wrong anyway) the compiler does a poor job in evaluating the expression in your question. Given that you wrote true ? param1 : param2 the compiler should determine right away that the first parameter -null- will be returned and it should generate a compiler error. This is somewhat similar to when you write while(true){} etc... and the compiler complains about the code underneath the loop and flags it with Unreachable Statements.

Your second case is pretty straightforward and this answer is already too long... ;)

CORRECTION:

After another analysis I believe that I was wrong to say that a null value can be boxed/autoboxed to anything. Talking about the class Integer, explicit boxing consists in invoking the new Integer(...) constructor or maybe the Integer.valueOf(int i); (I found this version somewhere). The former would throw a NumberFormatException (and this does not happen) while the second would just not make sense since an int cannot be null...

故事与诗 2024-12-22 05:02:19

实际上,在第一种情况下,可以对表达式进行求值,因为编译器知道它必须被计算为 Integer,但是在第二种情况下,返回值的类型 (null< /code>) 无法确定,因此无法编译。如果将其转换为Integer,代码将编译。

Actually, in the first case the expression can be evaluated, since the compiler knows, that it must be evaluated as an Integer, however in the second case the type of the return value (null) can not be determined, so it can not be compiled. If you cast it to Integer, the code will compile.

一梦浮鱼 2024-12-22 05:02:19
private int temp() {

    if (true) {
        Integer x = null;
        return x;// since that is fine because of unboxing then the returned value could be null
        //in other words I can say x could be null or new Integer(intValue) or a intValue
    }

    return (true ? null : 0);  //this will be prefectly legal null would be refrence to Integer. The concept is one the returned
    //value can be Integer 
    // then null is accepted to be a variable (-refrence variable-) of Integer
}
private int temp() {

    if (true) {
        Integer x = null;
        return x;// since that is fine because of unboxing then the returned value could be null
        //in other words I can say x could be null or new Integer(intValue) or a intValue
    }

    return (true ? null : 0);  //this will be prefectly legal null would be refrence to Integer. The concept is one the returned
    //value can be Integer 
    // then null is accepted to be a variable (-refrence variable-) of Integer
}
能怎样 2024-12-22 05:02:19

怎么样:

public class ConditionalExpressionType {

    public static void main(String[] args) {

        String s = "";
        s += (true ? 1 : "") instanceof Integer;
        System.out.println(s);

        String t = "";
        t += (!true ? 1 : "") instanceof String;
        System.out.println(t);

    }

}

输出是 true,true。

Eclipse 将条件表达式中的 1 颜色编码为自动装箱。

我的猜测是编译器将表达式的返回类型视为 Object。

How about this:

public class ConditionalExpressionType {

    public static void main(String[] args) {

        String s = "";
        s += (true ? 1 : "") instanceof Integer;
        System.out.println(s);

        String t = "";
        t += (!true ? 1 : "") instanceof String;
        System.out.println(t);

    }

}

The output is true, true.

Eclipse color codes the 1 in the conditional expression as autoboxed.

My guess is the compiler is seeing the return type of the expression as Object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文