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