Ошибка компиляции с обобщениями и троичным оператором в 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();
    }
}

Приведенный выше код не компилируется с javac с JDK 1.7.0_45:

$ 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 в Java 8, чтобы начать разрешать это - и если да, что было изменением?

1 ответ

Решение

JLS SE 8 говорит в ( §15.2):

Когда некоторые выражения появляются в определенных контекстах, они считаются поли выражениями. Следующие формы выражений могут быть выражениями поли:

  • Заключенные в скобки выражения (§15.8.5)

  • Выражения создания экземпляра класса (§15.9)

  • Выражения вызова метода (§15.12)

  • Выражения ссылки метода (§15.13)

  • Условные выражения (§15.25)

  • Лямбда-выражения (§15.27)

Таким образом, из этой части спецификации ясно, что условные выражения, тернарный оператор, могут рассматриваться как поли-выражения. Но не все условные выражения могут считаться поли выражениями, только ссылочные условные выражения согласно (§15.25). Условия, при которых ссылочное условное выражение может считаться поли-выражением, разъясняются в (§15.25.3):

Ссылочное условное выражение - это поли-выражение, если оно появляется в контексте присваивания или в контексте вызова (§5.2. §5.3). В противном случае это автономное выражение.

Когда условное выражение с поли-ссылкой появляется в контексте определенного вида с целевым типом T, его выражения второго и третьего операнда аналогичным образом появляются в контексте того же вида с целевым типом T.

Тип условного выражения с поли-ссылкой совпадает с его целевым типом.

Проверьте, что в вашем примере условное выражение появляется в контексте присваивания, потому что согласно (§14.17):

Когда в объявлении метода появляется оператор возврата с выражением, выражение должно быть присвоено (§5.2) объявленному типу возврата метода, иначе произойдет ошибка времени компиляции.

Итак, в конце концов, что все это значит? Это подразумевает, что когда условные выражения являются поли-выражениями, целевой тип "опускается" к каждому операнду. Таким образом, компилятор может приписывать каждую часть условия цели. В вашем случае цель List<String>, Если мы проверим определение метода emptyList(), то получим:

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

Так с целью List<String>компилятор может сделать вывод, что строка T == и код принят.

Другие вопросы по тегам