Тернарный оператор 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. Я думаю, большинство таких проблем будет исправлено до релиза.
главное отличие в том, что
ifelseблок сообщении в то время как троичный (чаще известный как условный оператор в Java) - это выражение.A сообщении может делать такие вещи, как
returnк вызывающему объекту на некоторых путях управления. Ан выражение может использоваться в задании:
int n = condition ? 3 : 2;Итак, два выражения в троичном после условие должно быть приведено к одному и тому же типу. Это может вызвать некоторые странные эффекты в Java, особенно с автоматическим боксом и автоматическим приведением ссылок - это то, на что ссылается комментарий в вашем опубликованном коде. Принуждение выражений в вашем случае было бы к
java.lang.reflect.Executableтип (как это самый специализированный тип) и это не существует в старых версиях Java.стилистически вы должны использовать
ifelseблок, если код оператор-как, и троичный, если это выражение-как.конечно, вы можете сделать
ifelseблок ведет себя как выражение, Если вы используете лямбда-функцию.