Какая разница в производительности, если таковая имеется, между if (! Foo) и if (foo == false) в Java?

Логически, if(!foo) и if(foo == false) эквивалентны. Как они представлены на Java? Есть ли разница между двумя после компиляции, либо в байте-коде или в производительности? Я не смог найти ответ в JLS, и поиск привел к большим результатам о действиях = vs. == typos и ==/equals(). (В этом случае символы мешали моему поиску, поскольку будущие искатели, оператор отрицания, равны ложному, равному false, а не условию).

Чтобы обсудить обсуждение CW: этот вопрос НЕ спрашивает, какой вариант предпочитают люди или который считается лучшим стилем. Меня интересуют различия в реализации языка, поэтому есть правильный ответ. Связанный-но-не-вполне-a-dupe: Разница между while (x = false) и while (! X) в Java?

EDIT:

По общему мнению, хороший компилятор должен оптимизировать их для одного и того же. Это имеет смысл и является тем, что я подозревал, но, чтобы задать еще более академический вопрос, - это то, что поведение действительно предусмотрено где угодно, или это "просто" разумная вещь?

Ответы

Ответ 1

JLS определит требуемое поведение операторов. Однако, как они реализованы, это деталь реализации компилятора и JVM.

На практике любой компилятор, заслуживающий своей соли, должен выпустить тот же байт-код для этих операторов. И даже если нет, JVM оптимизирует их правильно.

Кроме того, лучший способ ответить на этот вопрос - проверить сами, используя javap:

  • Скомпилируйте Test.java со следующим содержимым:

    class Test {
        void equals(boolean f) {
            if (f == false) {}
        }
        void not(boolean f) {
            if (!f) {}
        }
    }
    $ javac Test.java
    
  • Удалите его:

    $ javap -c Test
    Compiled from "Test.java"
    class Test extends java.lang.Object{
    Test();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   return
    
    void equals(boolean);
      Code:
       0:   iload_1
       1:   ifne    4
       4:   return
    
    void not(boolean);
      Code:
       0:   iload_1
       1:   ifne    4
       4:   return
    
    }
    

UPDATE: Отвечая на вопрос о "академическом" вопросе. Как упоминалось выше, JLS касается только поведения. В стандарте нет ничего, что на самом деле указывает, как оно должно быть реализовано (ну, JVMS предоставляет много рекомендаций).

Пока компилятор сохраняет одно и то же одинаковое поведение, компилятор может реализовать его по-разному, с возможностью различной производительности выполнения.

Ответ 2

Компилятор должен решить один и тот же код внутри, поэтому нет никакой разницы.

Ответ 3

попробуйте декомпилировать байтовый код и посмотреть, как выглядит код. Я бы предположил, что компиляция разрешит их почти одинаково, и любая небольшая разница приведет к незначительной разнице в производительности.

Ответ 4

ОК, более полный ответ:

Я был бы очень удивлен, если бы какой-либо компилятор сгенерировал разные байт-коды для этих вариантов. Для всех, кто интересуется, должно быть достаточно легко проверить с помощью дизассемблера.

Учитывая, что оба выражения (скорее всего) скомпилированы в один и тот же байт-код, я не ожидаю разницы в размере или производительности.

Ответ 5

JLS говорит, что

выражение в вычисляется блок if, тогда результат этого выражения сравнивается с правда

В случаях не случайных и сравниваемых объектов выражение должно оцениваться, а затем сравниваться с истинным. Если вы проверяете значение, а не выполняете оператор на нем, может быть теоретическое преимущество в производительности, так как оценка выражения становится не op.

Но в этом случае я бы ожидал, что JIT создаст тот же байт-код для обоих выражений.

Ответ 6

Не должно быть разницы в байт-коде, сгенерированном для этих двух результатов, и если бы это было сделано, если вы не создаете код для устройства с очень ограниченными ресурсами (в этом случае вы не должны писать на Java), чем разница была бы незначительной и вы должны решить, какой из двух способов написания этого кода является более очевидным решением.

Ответ 7

Мысль о микрооптимизации почти в любом случае является пустой тратой времени и приводит к неправильному мышлению...