<JDK8 兼容性中的 Java 三元运算符与 if/else
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32475166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java ternary operator vs if/else in <JDK8 compatibility
提问by jddxf
Recently I'm reading the source code of Spring Framework. Something I can't understand goes here:
最近在看Spring Framework的源码。我无法理解的东西在这里:
public Member getMember() {
// NOTE: no ternary expression to retain JDK <8 compatibility even when using
// the JDK 8 compiler (potentially selecting java.lang.reflect.Executable
// as common type, with that new base class not available on older JDKs)
if (this.method != null) {
return this.method;
}
else {
return this.constructor;
}
}
This method is a member of class org.springframework.core.MethodParameter
. The code is easy to understand while the comments are hard.
此方法是 class 的成员org.springframework.core.MethodParameter
。代码易懂,注释难。
NOTE: no ternary expression to retain JDK <8 compatibility even when using the JDK 8 compiler (potentially selecting
java.lang.reflect.Executable
as common type, with that new base class not available on older JDKs)
注意:即使在使用 JDK 8 编译器时也没有三元表达式来保持 JDK <8 的兼容性(可能选择
java.lang.reflect.Executable
为通用类型,新基类在旧 JDK 上不可用)
What's the difference between using ternary expression and using if...else...
construct in this context?
if...else...
在这种情况下使用三元表达式和使用构造有什么区别?
采纳答案by dhke
When you think about the type of the operands, the problem becomes more apparent:
当您考虑操作数的类型时,问题变得更加明显:
this.method != null ? this.method : this.constructor
has as type the most specialized common type of both the operands, i.e. the most specialized type common to both this.method
and this.constructor
.
一直类型两个操作数的最专业常见的类型,即最专业型通用于this.method
和this.constructor
。
In Java 7 this is java.lang.reflect.Member
, however the Java 8 class library introduces a new type java.lang.reflect.Executable
which is more specialized than the generic Member
. Hence with a Java 8 class library the result type of the ternary expression is Executable
rather than Member
.
在 Java 7 中是这样java.lang.reflect.Member
,但是 Java 8 类库引入了一种java.lang.reflect.Executable
比泛型更专业的新类型Member
。因此,对于 Java 8 类库,三元表达式的结果类型是Executable
而不是Member
.
Some (pre-release) versions of the Java 8 compiler seem to have produced an explicit reference to Executable
inside generated code when compiling the ternary operator. This would trigger a class load, and thus in turn a ClassNotFoundException
at runtime when running with a class library < JDK 8, because Executable
only exists for JDK ≥ 8.
Executable
在编译三元运算符时,Java 8 编译器的某些(预发布)版本似乎已经生成了对内部生成代码的显式引用。这将触发类加载,因此在ClassNotFoundException
使用类库 < JDK 8 运行时反过来又会在运行时触发,因为Executable
仅存在于 JDK ≥ 8。
As noted by Tagir Valeev in this answer, this is actually a bug in pre-release versions of JDK 8 and has since been fixed, so both the if-else
workaround and the explanatory comment are now obsolete.
正如 Tagir Valeev 在这个答案中所指出的,这实际上是 JDK 8 预发布版本中的一个错误,并且已经被修复,因此if-else
解决方法和解释性评论现在都已过时。
Additional note:One might come to the conclusion that this compiler bug was present before Java 8. However, the byte code generated for the ternary by OpenJDK 7 is the same as the byte code generated by OpenJDK 8. In fact, the type of the expression goes completely unmentioned at runtime, the code is really only test, branch, load, return without any additional checks going on. So rest assured that this is not a problem (anymore) and indeed seems to have been a temporary problem during development of Java 8.
附加说明:人们可能会得出结论,这个编译器错误在 Java 8 之前就存在。但是,OpenJDK 7 为三元生成的字节码与 OpenJDK 8 生成的字节码相同。实际上,表达式在运行时完全没有被提及,代码实际上只是测试、分支、加载、返回,没有进行任何额外的检查。所以请放心,这不是问题(不再),并且确实似乎是 Java 8 开发过程中的临时问题。
回答by Tagir Valeev
This was introduced in quite old commitat May 3rd, 2013, almost a year before official JDK-8 release. The compiler was under heavy development those times, so such compatibility problems could occur. I guess, the Spring team just tested the JDK-8 build and tried to fix problems, even though they are actually compiler problems. By JDK-8 official release this became irrelevant. Now the ternary operator in this code works fine as expected (no reference to Executable
class in compiled .class-file is present).
这是在2013 年 5 月 3 日,也就是 JDK-8 正式发布前将近一年的相当老的提交中引入的。当时编译器正在大力开发中,因此可能会出现此类兼容性问题。我猜,Spring 团队刚刚测试了 JDK-8 构建并试图修复问题,即使它们实际上是编译器问题。到 JDK-8 正式发布时,这变得无关紧要。现在此代码中的三元运算符按预期工作正常(不存在对Executable
编译的 .class-file 中的类的引用)。
Currently similar things appear in JDK-9: some code which can be nicely compiled in JDK-8 is failed with JDK-9 javac. I guess, most of such problems will be fixed till the release.
目前类似的事情出现在 JDK-9 中:一些可以在 JDK-8 中很好地编译的代码在 JDK-9 javac 中失败了。我想,大多数此类问题将在发布之前得到修复。
回答by Bathsheba
The chief difference is that an if
else
block is a statementwhereas the ternary (more often known as the conditionaloperator in Java) is an expression.
主要区别在于if
else
块是一个语句,而三元(在 Java 中通常称为条件运算符)是一个表达式。
A statementcan do things like return
to the caller on some of the control paths. An expressioncan be used in an assignment:
一言可以做这样的事情return
对某些控制路径的调用者。的表达可以在分配中使用:
int n = condition ? 3 : 2;
int n = condition ? 3 : 2;
So the two expressions in the ternary after the condition need to be coercable to the same type. This can cause some odd effects in Java particularly with auto-boxing and automatic reference casting - this is what the comment in your posted code is referring to. The coercion of the expressions in your case would be to a java.lang.reflect.Executable
type (as that's the most specialised type) and that does not exist in older versions of Java.
所以条件后的三元表达式中的两个表达式需要强制转换为同一类型。这可能会在 Java 中导致一些奇怪的效果,尤其是自动装箱和自动引用转换 - 这就是您发布的代码中的注释所指的内容。在您的情况下,表达式的强制转换将是一种java.lang.reflect.Executable
类型(因为这是最专业的类型)并且在旧版本的 Java 中不存在。
Stylistically you should use an if
else
block if the code is statement-like, and a ternary if it's expression-like.
从风格上讲,if
else
如果代码类似于语句,则应使用块,如果代码类似于表达式,则应使用三元。
Of course, you can make an if
else
block behave like an expression if you use a lambda function.
当然,if
else
如果您使用 lambda 函数,您可以使块的行为类似于表达式。
回答by user207421
The return value type in a ternary expression is affected by parent classes, which changed as described in Java 8.
三元表达式中的返回值类型受父类的影响,父类在 Java 8 中进行了更改。
Hard to see why a cast couldn't have been written.
很难理解为什么不能写演员表。