Тернарный оператор 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.

трудно понять, почему гипс не мог быть написан.