编写 if-else 编译器时会抱怨,但简而言之却没有,为啥? [复制]

Posted

技术标签:

【中文标题】编写 if-else 编译器时会抱怨,但简而言之却没有,为啥? [复制]【英文标题】:When writing if-else compiler complains but for shorthand it does not, why? [duplicate]编写 if-else 编译器时会抱怨,但简而言之却没有,为什么? [复制] 【发布时间】:2015-03-17 16:42:03 【问题描述】:

当我这样写时在 Java 中

public int method(boolean b) 
    if (b)
        return null;
    else
        return 0;

编译器抱怨incompatible types,但如果用速记代替它

public int method(boolean b) 
    return (b ? null : 0);

编译器不会报错,而且会有NPE。 所以我的问题是

    为什么编译器不抱怨 为什么是NPE

【问题讨论】:

2. NPE 因为 Integer.intValue() 在 null 上调用。原始类型 int 不能为 null, 【参考方案1】:

这是由自动拆箱和类型推断共同造成的。

在这两种情况下,从类型签名中可以清楚地看出该方法必须返回一个int

在您的第一种情况下,您显式返回null,它不能分配给int,因此编译器正确地抱怨这是一个错误。

在第二种情况下,您正在创建一个匿名值(括号中的位),因此编译器必须推断它的类型。事实证明,0null 最具体的常见超类型是 Integer - 这是正确的。因此,您的 return 语句返回了 Integer 类型的东西——并且这个 int 兼容,它只是在运行时自动拆箱。当 VM 尝试将空引用转换为 int 时,正是这种自动拆箱引发了 NPE。

如果它可以帮助您更好地对其进行可视化,那么您的第二个示例与以下示例基本相同:

public int method(boolean b) 
    Integer tmp = (b ? null : 0);
    return tmp;

因此编译器没有什么可抱怨的(这两行本身都很好)。

这里的错误,如果有的话,是自动拆箱,并默默地假装Integerint是同一类型。不是,正是因为这个原因。

【讨论】:

啊,这就解释了为什么第一个示例中的return (Integer) null; 使编译错误消失了,但在运行时保留了 NPE。 更像return tmp.intValue() @OldCurmudgeon return tmp; 工作正常,您不需要显式调用 intValue(),因为 Java 会自动拆箱而不会抱怨。 @azurefrog - 正确 - 但它更清楚地展示了 NPE 的来源。 第二种情况与“匿名值”无关。使用的ternary operator rule 是:“第 2/3 个操作数之一是原始类型 T,另一个的类型是对 T 应用装箱转换的结果,则类型 ... 是 T i>":因此它将三元的结果评估为int,可以返回(§14.17),因为它可以分配给int。这就是该方法编译的原因。然后将字节码编译为Integer.intValue()null(不幸的是,先装箱然后再拆箱0),这会在运行时抛出NPE。【参考方案2】:

问题在于您要返回的类型。 您不能将 null 分配给原始类型。 这是一个半答案我不知道为什么它在速记版本中没有抱怨。

【讨论】:

字符串不是原始类型。 真的!我有点心烦意乱,因为工作太多。我会更正答案。

以上是关于编写 if-else 编译器时会抱怨,但简而言之却没有,为啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

彻底消灭if-else嵌套

彻底消灭if-else嵌套

StreamReader 抱怨文件不存在,但确实存在

为啥 sip 在使用 char * 时会抱怨意外类型“str”?

利用CPU的分支预测(Branch Prediction)模型优化if-else

严格验证可空字段[重复]