Тернарный оператор Java vs if / else in
недавно я читаю исходный код 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 java.lang.reflect.Executable как общий тип, с этим новым базовым классом, недоступным на старых JDKs)
что разница между использованием тернарного выражения и использованием if...else...
построить в этом контексте?
4 ответа:
когда вы думаете о типе операндов, проблема становится все более очевидной:
this.method != null ? this.method : this.constructor
имеет в качестве типа наиболее специализированный общий тип обоих операндов, т. е. наиболее специализированный тип, общий для обоих
this.method
иthis.constructor
.в Java 7 это
java.lang.reflect.Member
, однако библиотека классов Java 8 вводит новый типjava.lang.reflect.Executable
который является более специализированным, чем общийMember
. Следовательно, с библиотекой классов Java 8 тип результата тернарного выраженияExecutable
, а неMember
.некоторые (предрелизные) версии компилятора Java 8, похоже, произвели явную ссылку на
Executable
внутри сгенерированного кода при компиляции тернарный оператор. Это вызовет загрузку класса, и, следовательно, в свою очередь aClassNotFoundException
во время выполнения при работе с библиотекой классов Executable существует только для JDK ≥ 8.как отметил Тагир Валеев в ответ этот на самом деле это ошибка в предрелизных версиях JDK 8 и с тех пор была исправлена, так что оба
if-else
обходной путь и пояснительный комментарий теперь устарели.дополнительная информация: можно было бы прийти к выводу, что эта ошибка компилятора присутствовала до Java 8. Однако, сгенерированного байт-кода в троичный на пакеты OpenJDK 7 такой же, как и байт-код, генерируемые пакеты OpenJDK 8. Фактически, тип выражения полностью не упоминается во время выполнения, код является действительно только тест, ветка, загрузка, возврат без каких-либо дополнительных проверок. Так что будьте уверены, что это не проблема (больше) и действительно, кажется, была временная проблема во время разработки Java 8.
Это было представлено в довольно старый commit 3 мая 2013 года, почти за год до официального выпуска JDK-8. Компилятор в то время находился в тяжелом развитии, поэтому такие проблемы совместимости могли возникнуть. Я думаю, команда Spring только что протестировала сборку JDK-8 и попыталась исправить проблемы, хотя на самом деле это проблемы компилятора. К официальному выпуску JDK-8 это стало неуместным. Теперь тернарный оператор в этом коде работает нормально, как и ожидалось (нет ссылки на
Executable
класс в скомпилированном виде .класс-файл присутствует).В настоящее время подобные вещи появляются в JDK-9: некоторый код, который может быть хорошо скомпилирован в JDK-8, не удался с JDK-9 javac. Я думаю, большинство таких проблем будет исправлено до релиза.
главное отличие в том, что
if
else
блок сообщении в то время как троичный (чаще известный как условный оператор в Java) - это выражение.A сообщении может делать такие вещи, как
return
к вызывающему объекту на некоторых путях управления. Ан выражение может использоваться в задании:
int n = condition ? 3 : 2;
Итак, два выражения в троичном после условие должно быть приведено к одному и тому же типу. Это может вызвать некоторые странные эффекты в Java, особенно с автоматическим боксом и автоматическим приведением ссылок - это то, на что ссылается комментарий в вашем опубликованном коде. Принуждение выражений в вашем случае было бы к
java.lang.reflect.Executable
тип (как это самый специализированный тип) и это не существует в старых версиях Java.стилистически вы должны использовать
if
else
блок, если код оператор-как, и троичный, если это выражение-как.конечно, вы можете сделать
if
else
блок ведет себя как выражение, Если вы используете лямбда-функцию.