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