为什么 Java 评估三元运算的错误一面?

Why is Java evaluating the wrong side of ternary operation?

我可能会漏掉一些简单的解释,但下面这行会抛出一个 NullPointerException:

Long sum = true 
           ? 
           fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) 
           :
           (long) fiscalDocument.getReceipt().getAmount();

同时

Long sum = true 
           ? 
           fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) 
           :
           null

没有。我还想提一下

fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice())

不会自行抛出异常,而

(long) fiscalDocument.getReceipt().getAmount()

会。

第二面评价了吗?还是我在屠杀什么东西?

编辑

一些额外的信息,在评论中询问: fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) return 为空。 fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) 的 return 类型是 Long。

fiscalDocument.getReceipt().getAmount()的return类型是Integer

如果我发出显式(长)转换,行为是相同的。

编辑 2

一个最小的可重现示例:Long val =true ? (Long) null: Integer.valueOf(1);。 MC Emperor 的回答部分暗示了这一点,评论部分暗示了这一点。当然,这个例子已经在一定程度上回答了这个问题,因为事实证明,第二个表达式不需要抛出异常。

如果 foo 的类型为 Long 并且 bar 的类型为 long,则 true ? foo : bar 的类型为 long,并且等同于true ? foo.longValue() : bar。作为 Java 语言规范 puts it:

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.

(在您的例子中,Tlong,“将装箱转换 (§5.1.7) 应用于 T 的结果”是 Long。)

您尝试将结果放入 Long 变量这一事实并没有改变这一事实;它只是给你相当于 Long.valueOf(true ? foo.longValue() : bar),先拆箱再装箱。

在你的情况下,foo == null,所以拆箱会抛出 NullPointerException,所以装箱永远不会发生。

嗯,Java 只计算左边的表达式,因为条件是 true

你说 fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) 本身不会抛出 NullPointerException。

我唯一能想到的,就是fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice())returnsnull。可重现:

Long sum = true ? null : (long) 23L;

因为其中一个操作数是基元,另外一个是装箱转换,本例拆箱为long