Java三元运算符与<JDK8兼容性中的if / else

最近我正在阅读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;
    }
}

此方法是类org.springframework.core.MethodParameter的成员。 代码很容易理解,而评论很难。

注意:即使使用JDK 8编译器(可能选择java.lang.reflect.Executable作为常见类型,而新的基类在旧JDK上不可用),也不会保留JDK <8兼容性的三元表达式。

在这种情况下使用三元表达式和使用if...else...构造之间有什么区别?


当你考虑操作数的类型时,问题就会变得更加明显:

this.method != null ? this.method : this.constructor

具有两种操作数的最常用类型,即this.methodthis.constructor共有的最专用类型。

在Java 7中,这是java.lang.reflect.Member ,但是Java 8类库引入了一种新类型的java.lang.reflect.Executable ,它比通用Member更专业。 因此,对于Java 8类库,三元表达式的结果类型是Executable而不是Member

在编译三元运算符时,Java 8编译器的一些(预发布)版本似乎在生成的代码中显式引用了Executable 。 这会触发类加载,并因此在运行时使用类库<JDK 8运行时ClassNotFoundException ,因为Executable仅在JDK≥8时存在。

正如Tagir Valeev在回答中所指出的那样,这实际上是JDK 8的预发布版本中的一个错误,并且已经被修复,所以if-else解决方法和解释性评论现在都已过时。

补充说明:可能会得出这样的结论:该编译器错误在Java 8之前出现。但是,由OpenJDK 7为三元生成的字节代码与由OpenJDK 8生成的字节代码相同。事实上,表达式在运行时完全没有提到,代码实际上只是测试,分支,加载,返回而没有进行任何额外的检查。 因此,请放心,这不是一个问题(现在已经),而且在Java 8开发过程中似乎确实是一个暂时的问题。


这是在2013年5月3日相当古老的版本中提出的,距JDK-8正式发布差不多一年。 编译器在那个时候处于繁重的开发中,所以可能会出现这种兼容性问题。 我想,Spring团队只是测试了JDK-8构建,并试图解决问题,即使它们实际上是编译器问题。 通过JDK-8官方发布,这变得无关紧要。 现在,此代码中的三元运算符按预期正常工作(不存在对已编译的.class-file中的Executable类的引用)。

目前在JDK-9中出现类似的情况:JDK-8中可以很好编译的代码在JDK-9 javac中失败。 我想,这些问题大部分都会在发布之前得到修复。


主要区别在于if else块是一个语句,而三元(更常称为Java中的条件运算符)是一个表达式。

一条语句可以做一些事情,例如在一些控制路径上return给调用者。 表达式可以用于赋值中:

int n = condition ? 3 : 2;

因此,条件之后的三元表达式需要被强制为相同的类型。 这可能会在Java中引起一些奇怪的效果,特别是在自动装箱和自动引用投射方面 - 这就是您的发布代码中的评论所指的。 在你的情况下,表达式的强制转化为java.lang.reflect.Executable类型(因为这是最专业化的类型),并且在旧版本的Java中不存在。

在风格上,如果代码类似于语句,则应该使用if else块;如果类似表达式,则使用三元。

当然,如果你使用lambda函数,你可以使if else块的行为像表达式一样。

链接地址: http://www.djcxy.com/p/91883.html

上一篇: Java ternary operator vs if/else in <JDK8 compatibility

下一篇: Error generating report with JDK8