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

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 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 блок ведет себя как выражение, Если вы используете лямбда-функцию.

тип возвращаемого значения в тернарном выражении зависит от родительских классов, которые изменились, как описано в Java 8.

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