Является ли CONSTANT.equals(VARIABLE) быстрее, чем VARIABLE.equals(CONSTANT)?

У меня был интересный разговор с одним из моих товарищей по команде.

Является CONSTANT.equals(VARIABLE) быстрее, чем VARIABLE.equals(CONSTANT) в Java?

Я подозреваю, что это ложное утверждение. Но я пытаюсь выяснить, какими должны быть качественные рассуждения за этим?

Я знаю, что в обоих случаях производительность не будет отличаться от какого-либо значимого состояния. Но это была рекомендация по ЛУЧШЕЙ ПРАКТИКЕ, которая вызывает у меня дискомфорт. Это причина, по которой я смотрю на хорошие рассуждения, которые я хочу представить в этом случае.

ПОМОГИТЕ ПОМОЩЬ

Ответ 1

Интересный вопрос. Вот тест, который я написал:

public class EqualsTest {
    public static String CONST = "const";
    public void constEqVar(String var) {
        CONST.equals(var);
    }
    public void varEqConst(String var) {
        var.equals(CONST);
    }
}

Затем я скомпилировал его с помощью javac: javac EqualsTest.java и разобрал его с помощью javap: javap -c EqualsTest.

Вот соответствующий фрагмент выхода javap:

public void constEqVar(java.lang.String);
  Code:
   0:   getstatic       #2; //Field CONST:Ljava/lang/String;
   3:   aload_1
   4:   invokevirtual   #3; //Method java/lang/String.equals:(Ljava/lang/Object;)Z
   7:   pop
   8:   return

public void varEqConst(java.lang.String);
  Code:
   0:   aload_1
   1:   getstatic       #2; //Field CONST:Ljava/lang/String;
   4:   invokevirtual   #3; //Method java/lang/String.equals:(Ljava/lang/Object;)Z
   7:   pop
   8:   return

Как вы можете видеть, единственная разница между тезисами 2 метода - порядок операций: getstatic, а затем aload_1 в первом случае и aload_1 + getstatic во втором случае.

Довольно очевидно, что время выполнения не должно зависеть от этого порядка.

Единственная причина, чтобы предпочесть const.equals(var), а не var.equals(const), - это избегать NullPointerException.

Ответ 2

Для меня это не проблема скорости, ее проблема с возможностью переноса.

например.

"Hello".equals(a); // will never throw a NPE
a.equals("Hello"); // can throw an NPE.

Вы можете предпочесть его взорвать, когда a null, но обычно я этого не делаю.

Ответ 3

Это зависит только от реализации метода equals. Это может быть быстрее, это может быть медленнее, и это может быть одинаково... Часто это одно и то же. Также это не зависит от того, что один является переменной, а другой константой, но для содержимого обоих объектов.

Одно из преимуществ Constant.equals(variable) заключается в том, что вы не можете иметь исключение NullPointerException в .equals

Ответ 4

Сделал простой тест со строками:

final String constHello = "Hello";
final int times = 1000000000;

long constTimeStart = System.nanoTime();

for (int i = 0; i < times; ++i) {
    constHello.equals("Hello");
}

long constTimeStop = System.nanoTime();

System.out.println("constHello.equals(\"Hello\"); " + times + " times: " + (constTimeStop - constTimeStart) + " ns");


constTimeStart = System.nanoTime();

for (int i = 0; i < times; ++i) {
    "Hello".equals(constHello);
}

constTimeStop = System.nanoTime();

System.out.println("\"Hello\".equals(constHello); " + times + " times: " + (constTimeStop - constTimeStart) + " ns");

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

Ответ 5

Если мы сравним ключ CONSTANT (левая часть метода equals) с любым объектом (правая часть метода equals), то компилятор может проверить сравнение и дать ожидаемый результат, но если мы сделаем наоборот Object ((левая часть метода equals)) сравнение с ключом константы ((справа от метода equals)), тогда ваша программа может выполнить исключение NULL POINTER.

public static void main(String[] args) {
    String CONSTANT_KEY = "JAVA";
    String string = null;

    // CASE 1
    if (CONSTANT_KEY.equals(string)) {
        System.out.println("I am in if block");
    }

    // CASE 2   
    if (string.equals(string)) {
        System.out.println("I am in if block");
    }
}

В приведенном выше примере кода 1 всегда безопасно сравнивать объекты, чтобы исключить исключение NULL POINTER вместо случая 2.

Ответ 6

Я думаю, код в java.lang.String поддерживает мой ответ:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = offset;
            int j = anotherString.offset;
            while (n-- != 0) {
                if (v1[i++] != v2[j++])
                    return false;
            }
            return true;
        }
    }
    return false;
}

Ответ 7

Одно хорошее сравнение может быть:

private static String EXAMPLE = "Example";
private String obj = null;

случай 1:

if(obj.equals(EXAMPLE) {
}

Это исключение исключения null-указателя.

случай 2:

if(EXAMPLE.equals(obj)) {
}

Это не приведет к исключению исключения с нулевым указателем.