Java,为什么有人对三元运算符这样做?

Java,为什么有人对三元运算符这样做?,java,Java,为什么会有人这样做 int foo; foo = (true?this.getFoo() : 0); //getFoo() returns int 它突然出现了一堆,我真的不明白为什么这不总是等同于: int foo = this.getFoo(); 这仅用于int类型的变量,并使用返回int的getter。字符串没有得到相同的处理 编辑以包含答案:(来自安迪·特纳的评论) 关于“是真的吗?getFoo()”:0在逻辑上等价 to getFoo()”:这在语言规范中得到了回答,其中说明: 如

为什么会有人这样做

int foo;
foo = (true?this.getFoo() : 0); //getFoo() returns int
它突然出现了一堆,我真的不明白为什么这不总是等同于:

int foo = this.getFoo();
这仅用于int类型的变量,并使用返回int的getter。字符串没有得到相同的处理

编辑以包含答案:(来自安迪·特纳的评论)

关于“是真的吗?getFoo()”:0在逻辑上等价 to getFoo()”:这在语言规范中得到了回答,其中说明: 如果第一个操作数的值为真,则第二个操作数 表达式已选择。”(和“未选择的操作数表达式未被选择 为条件的特定求值而求值 表达式”,但在本例中,如果0为 评估后丢弃,因为 (评估)


在这种情况下,绝对没有理由使用三元。

如果
this.getFoo()
是一个
整数,
Short
Byte
,这可能会触发使用条件运算符取消装箱的一些反常行为

例如,如果
this.getFoo()
返回
null
,则此表达式将导致
NullPointerException

除了玩具的例子,没有很好的理由写这个

如果
this.getFoo()
返回一个基元类型,那么绝对没有理由编写它<代码>foo=真?this.getFoo():0
相当于
foo=this.getFoo()

语言规范的相关章节如下所示:

如果第一个操作数的值为真,则选择第二个操作数表达式

(它还说:

未选择的操作数表达式不会针对条件表达式的特定计算进行计算

尽管在这种情况下,如果对0进行评估然后将其丢弃并不重要,因为评估它没有副作用)


条件运算符在装箱和取消装箱方面有一些非常特殊的行为。例如:

condition ? 0 : null
框住
0
,因此始终成功;但是

condition ? 0 : (Integer) null
取消对
null
的装箱,因此当
条件
为false时,
NullPointerException
将失败

值得注意的是,这是

true ? Integer.valueOf(0) : Double.valueOf(0)
是一个
Double

使用嵌套的条件表达式,它变得更加隐蔽,例如

Integer i = condition1 ? 1 : condition2 ? 2 : null;
因为整个表达式的类型是
int
,而不是
Integer
,所以您可以得到
NullPointerException
,尽管它看起来像是得到一个
Integer
,因为您将赋值给
Integer
类型的变量。实际上,它的评估是这样的:

Integer i = Integer.valueOf(condition1 ? 1 : (condition2 ? Integer.valueOf(2) : null).intValue()));

条件运算符有一些非常复杂的规则,只有在涉及盒式数字类型时才应小心使用。

三元运算符毫无意义:条件始终为真

就好像你写过:

foo =  this.getFoo();
下面是一个三元数有意义的例子。
假设
this.fetFoo()
返回一个可能为
null
Integer
,您可以编写此代码以防止出现
NullPointerException

int foo = this.getFoo() == null ? 0 : this.getFoo();
或者不重复调用
this.getFoo()
,但更详细:

Integer fooInteger = this.getFoo();
int foo = fooInteger == null ? 0 : fooInteger;


它将始终是foo=this.getFoo(),除非他们设法更改了true的值。也许你应该问编写此代码的人this.getFoo()的类型是什么?this.getFoo()返回intIn在这种情况下,你的第一个调用端口应该是询问作者。在这里,您比我们有更多的上下文:我们不知道您正在查看的是哪段代码。它是开源的吗?公司代码?还有别的吗?@Nathan可能是因为他写了这样的代码,所以他才大发雷霆。在哪种情况下,你会看到int foo=(true?this.getFoo():null);如果this.getFoo()返回null,则不会以NPE结尾?@Stultuske措词不当。你的第一句话是什么意思,关于拆箱的问题conditional@Nathan我已经用一些例子扩展了我的答案。你能详细说明一下吗?例如,指向规范中明确说明此表达式始终重写为
this.getFoo()
,或显示一些反编译示例的部分?@AndreyTyukin它并不总是重写为该部分。只是没有理由写这篇文章。@AndyTurner你似乎把两个截然不同的领域混为一谈了。“没有理由”是一个哲学陈述,似乎在说明编写代码的人可能的动机。关于这一点我不能说什么,也许写这篇文章的人从写不可理解的代码中获得了某种奇怪的乐趣。我所寻找的是一个关于Java语义的陈述:“
true?bar:baz
总是被重写为
bar
”是一个关于编程语言语义的精确可验证的陈述,它不涉及任何心理学或哲学OK,这里有一个精确的陈述:
true?bar:baz
不需要重写为该值。你在说明书中找不到任何说明它能做到这一点的东西。编译器或JIT可能会对其进行优化,但这不是必需的。我可以验证原始作者确实从编写不可理解的代码中获得了乐趣。您的代码非常有意义。但它并没有回答关于代码的问题,这似乎毫无意义。@Andrey Tyukin你说得对。我重新编写了解释无关性和有效用例的引入。我对此很熟悉,但是。。。您想在使用getter时处理此问题吗?为什么不在getter本身呢?理想情况下是的。但是,由于多种原因,这可能是不可能的:因为一些开发人员避免使用getter中的逻辑,或者因为它是一个库代码。