java三元运算符用的多不多_java – JDK8和JDK10上三元运算符的行为差异

我相信这是一个似乎已经解决的错误.根据JLS,抛出NullPointerException似乎是正确的行为.

我认为这里发生的是由于某些原因在版本8中,编译器考虑了方法的返回类型提到的类型变量的边界而不是实际的类型参数.换句话说,它认为… get(“1”)返回Object.这可能是因为它正在考虑方法的擦除或其他原因.

该行为应取决于get方法的返回类型,如下面的§15.26摘录所指定:

If both the second and the third operand expressions are numeric expressions, the conditional expression is a numeric conditional expression.

For the purpose of classifying a conditional, the following expressions are numeric expressions:

[…]

A method invocation expression (§15.12) for which the chosen most specific method (§15.12.2.5) has a return type that is convertible to a numeric type.

Note that, for a generic method, this is the type before instantiating the method’s type arguments.

[…]

Otherwise, the conditional expression is a reference conditional expression.

[…]

The type of a numeric conditional expression is determined as follows:

[…]

If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

换句话说,如果两个表达式都可以转换为数字类型,并且一个是基本的而另一个是盒装的,则三元条件的结果类型是基本类型.

(表15.25-C还方便地向我们展示了三元表达式boolean的类型?double:Double确实是双倍的,再次意味着拆箱和投掷是正确的.)

如果get方法的返回类型不可转换为数字类型,则三元条件将被视为“引用条件表达式”,并且不会发生拆箱.

另外,我认为注释“对于泛型方法,这是在实例化方法的类型参数之前的类型”不应该适用于我们的情况. Map.get没有声明类型变量,so it’s not a generic method by the JLS’ definition.但是,这个注释是在Java 9中添加的(唯一的变化,see JLS8),因此它可能与我们今天看到的行为有关.

对于HashMap< String,Double>,get的返回类型应为Double.

这是一个支持我的理论的MCVE,编译器正在考虑类型变量边界而不是实际的类型参数:

class Example {

N nullAsNumber() { return null; }

D nullAsDouble() { return null; }

public static void main(String[] args) {

Example e = new Example<>();

try {

Double a = false ? 0.0 : e.nullAsNumber();

System.out.printf("a == %f%n", a);

Double b = false ? 0.0 : e.nullAsDouble();

System.out.printf("b == %f%n", b);

} catch (NullPointerException x) {

System.out.println(x);

}

}

}

a == null

java.lang.NullPointerException

换句话说,尽管e.nullAsNumber()和e.nullAsDouble()具有相同的实际返回类型,但只有e.nullAsDouble()被视为“数字表达式”.方法之间的唯一区别是类型变量绑定.

可能会有更多的调查,但我想发布我的发现.我尝试了很多东西,发现只有当表达式是返回类型中带有类型变量的方法时,才会发生错误(即没有取消装箱/ NPE).

import java.util.*;

class Example {

static void accept(Double d) {}

public static void main(String[] args) {

accept(false ? 1.0 : new HashMap().get("1"));

}

}

这表明编译器的行为实际上是不同的,这取决于三元表达式是分配给局部变量还是方法参数.

(最初我想使用重载来证明编译器给三元表达式赋予的实际类型,但鉴于上述差异,它看起来不太可能.有可能还有另一种我没有想到的方法,虽然.)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值