JDK 7中的泛型和三元运算符的编译错误

编写一些Java代码时遇到了编译失败,我将其解压缩到以下测试用例:

import java.util.Collections;
import java.util.List;

public class TernaryFailure {
    public static List<String> thisWorks() {
        return Collections.emptyList();
    }

    public static List<String> thisFailsToCompile() {
        return true ? Collections.emptyList() : Collections.emptyList();
    }
}

上面的代码无法使用JDK 1.7.0_45的javac进行编译:

$ javac TernaryFailure.java
TernaryFailure.java:10: error: incompatible types
        return true ? Collections.emptyList() : Collections.emptyList();
                    ^
  required: List<String>
  found:    List<Object>
1 error

但是,它编译时没有出现任何与JDK 1.8.0_05有关的错误。

这是Java 7实现中的一个错误吗? 或者是否对Java 8中的Java语言规范进行了改进以开始允许这一点 - 如果是的话,那么改变是什么?


JLS SE 8在(§15.2)中说:

当某些表达式出现在某些上下文中时,它们被视为多表达式。 以下表达形式可以是多表达式:

  • 括号表达式(§15.8.5)

  • 类实例创建表达式(第15.9节)

  • 方法调用表达式(第15.12节)

  • 方法引用表达式(第15.13节)

  • 条件表达式(§15.25)

  • Lambda表达式(§15.27)

  • 所以从这部分规范中可以明显看出,条件表达式,即三元运算符可以被认为是多表达式。 但并不是所有的条件表达式都可以被认为是多表达式,只有根据(§15.25)引用条件表达式。 (§15.25.3)阐明了参考条件表达式可以视为多表达式的条件:

    如果引用条件表达式出现在赋值上下文或调用上下文中(§5.2。§5.3),则它是一个多表达式。 否则,这是一个独立的表达。

    当多参考条件表达式出现在具有目标类型T的特定种类的上下文中时,其第二和第三操作数表达式类似地出现在与目标类型T相同类型的上下文中。

    多引用条件表达式的类型与其目标类型相同。

    检查在你的例子中,条件表达式出现在赋值语境中,因为根据(§14.17):

    当具有Expression的返回语句出现在方法声明中时,Expression必须可分配给该方法的声明返回类型(第5.2节),否则会发生编译时错误。

    所以在一天结束时,这意味着什么? 这意味着当条件表达式是多表达式时,目标类型被“下推”到每个操作数。 通过这种方式,编译器可以将条件的每个部分都归于目标。 在你的情况下,目标是List<String> 。 如果我们检查emptyList()方法的定义,我们有:

    @SuppressWarnings("unchecked")
    public static final <T> List<T> emptyList() {
        return (List<T>) EMPTY_LIST;
    }
    

    因此,对于目标List<String> ,编译器可以推断出T == String并且代码被接受。

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

    上一篇: Compilation error with generics and ternary operator in JDK 7

    下一篇: node.js