Вопреки ответам Павла Хорала, Codo и yuvgin Я утверждаю, что компилятор НЕ оптимизирует (или игнорирует) тернарный оператор. (Пояснение: я имею в виду компилятор Java в байт-код, а не JIT)
Смотрите тестовые примеры.
Класс 1: оценивает логическое выражение, сохраняет его в переменной и возвращает эту переменную.
public static boolean testCompiler(final int a, final int b)
{
final boolean c = ...;
return c;
}
Итак, для разных булевых выражений проверяем байт-код: 1. Выражение: a == b
Байт-код
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: istore_2
11: iload_2
12: ireturn
- Выражение:
a == b ? true : false
Байт-код
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: istore_2
11: iload_2
12: ireturn
- Выражение:
a == b ? false : true
Байт-код
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_0
6: goto 10
9: iconst_1
10: istore_2
11: iload_2
12: ireturn
Случаи (1) и (2) компилируются в один и тот же байт-код не потому, что компилятор оптимизирует тернарный оператор, а потому, что ему необходимо каждый раз выполнять этот тривиальный тернарный оператор. На уровне байт-кода необходимо указать, следует ли возвращать true или false. Чтобы убедиться в этом, посмотрите на случай (3). Это точно такой же байт-код, за исключением строк 5 и 9, которые поменялись местами.
Что происходит тогда и a == b ? true : false
при декомпиляции дает a == b
? Это выбор декомпилятора, который выбирает самый простой путь.
Кроме того, на основе эксперимента «Класс 1» разумно предположить, что a == b ? true : false
точно такое же, как a == b
в том, как оно транслируется в байт-код. Однако это не так. Чтобы проверить это, мы исследуем следующий «Класс 2», единственная разница с «Классом 1» заключается в том, что он не сохраняет логический результат в переменной, а вместо этого немедленно возвращает его.
Класс 2: оценка логического выражения и возврат результата (без сохранения его в переменной).
public static boolean testCompiler(final int a, final int b)
{
return ...;
}
Байт-код:
0: iload_0
1: iload_1
2: if_icmpne 7
5: iconst_1
6: ireturn
7: iconst_0
8: ireturn
Байт-код
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: ireturn
Байт-код
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_0
6: goto 10
9: iconst_1
10: ireturn
Здесь очевидно, что a == b
и a == b ? true : false
выражения компилируются по-разному, так как случаи (1) и (2) дают разные байт-коды (случаи (2) и (3), как и ожидалось, поменялись местами только их строки 5,9).
Сначала это меня удивило, так как я ожидал, что все 3 случая будут одинаковыми (за исключением переставленных строк 5,9 случая (3)). Когда компилятор встречает a == b
, он оценивает выражение и сразу после него возвращается, в отличие от встречи с a == b ? true : false
, где он использует goto
для перехода к строке ireturn
. Я понимаю, что это сделано для того, чтобы оставить место для оценки потенциальных утверждений внутри «истинного» случая тернарного оператора: между проверкой if_icmpne
и строкой goto
. Даже если в данном случае это просто логическое значение true
, компилятор обрабатывает его так же, как в общем случае, когда присутствует более сложный блок.
С другой стороны, "класс 1" скрыл этот факт, так как в ветке true
были также istore
, iload
и не только ireturn
, форсирующие команду goto
и приводившие к точно такому же байт-коду в случаях (1) и (2).
В качестве примечания относительно тестовой среды: эти байт-коды были созданы с помощью последней версии Eclipse (4.10), в которой используется соответствующий компилятор ECJ, отличный от javac, который использует IntelliJ IDEA.
Однако, читая созданный javac байт-код в других ответах (которые используют IntelliJ), я считаю, что та же логика применима и там, по крайней мере, для эксперимента «Класс 1», где значение было сохранено и не возвращено немедленно.
Наконец, как уже указывалось в других ответах (например, от supercat и jcsahnwaldt) , как в этой теме, так и в других вопросах SO тяжелая оптимизация выполняется компилятором JIT, а не компилятором java-->java-bytecode, поэтому эти проверки, хотя и информативные для перевода байт-кода, не являются хорошей мерой того, как будет выполняться окончательный оптимизированный код.
Дополнение: ответ jcsahnwaldt сравнивает созданный javac и ECJ байт-код для аналогичных случаев.
(В качестве отказа от ответственности: я не изучал компиляцию или дизассемблирование Java так много, чтобы на самом деле знать, что он делает под капотом; мои выводы в основном основаны на результатах приведенных выше экспериментов.)
person
tryman
schedule
02.02.2019
if( foo == true )
для удобочитаемости? - person Roddy of the Frozen Peas   schedule 02.02.2019if ( isValid(input) ? true : false )
. - person Paul   schedule 02.02.2019int x = y
читается естественно, если установить целое число x в y, ноbool z = x == y
читается как установить логическое значение z на x равно y, что звучит забавно. - person Challenger5   schedule 03.02.2019if (foo == false)
, потому что думают, что!
трудно различить в!foo
... - person Bakuriu   schedule 03.02.2019if ( (isValid(input) ? true : false) == true )
- person JJJ   schedule 03.02.2019