Влияет ли порядок проверки на равенство на производительность в Java? - PullRequest
0 голосов
/ 16 марта 2012

Я обычно пишу такой код:

private List<Foo> fooList = new ArrayList<Foo>();

public Foo findFoo(FooAttr attr) {
    for(Foo foo : fooList) {
        if (foo.getAttr().equals(attr)) {
            return foo;
        }
    }
}

Однако, предполагая, что я правильно защищаюсь от нулевого ввода, я мог бы также выразить цикл следующим образом:

for(Foo foo : fooList) {
    if (attr.equals(foo.getAttr()) {
        return foo;
    }
}

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

В частности, мне интересно, может ли вторая форма быть более производительной, потому что метод equals() вызывается неоднократно для одного и того же объекта, а не для разных объектов? Может быть, прогноз отрасли является фактором?

Ответы [ 6 ]

4 голосов
/ 16 марта 2012

Я бы предложил здесь 2 совета:

  1. Измерьте его
  2. Если ничто иное не указывает вам в каком-либо направлении, предпочтите форму, которая наиболее логична и звучит наиболее естественнокогда вы говорите это вслух (или в своей голове!)
2 голосов
/ 16 марта 2012

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

2 голосов
/ 16 марта 2012

Я думаю, что, учитывая предсказание ветвления, мы беспокоимся об эффективности на слишком низком уровне. Однако я нахожу второй пример вашего кода более читабельным, потому что вы ставите согласованный объект первым. Точно так же, если бы вы сравнивали this с другим объектом that, я бы поставил this первым.

Конечно, equals определяется программистом, поэтому он может быть асимметричным. Вы должны сделать равным отношение эквивалентности , так что это не должно иметь место. Даже если у вас есть отношение эквивалентности, порядок может иметь значение. Предположим, что attr является суперклассом различных foo.getAttr, и первый тест вашего equals метода проверяет, является ли другой объект экземпляром того же класса. Затем attr.equals(foo.getAttr()) пройдет первую проверку, но foo.getAttr().equals(attr) не пройдет первую проверку.

Однако беспокойство по поводу эффективности на этом уровне редко дает преимущества.

1 голос
/ 16 марта 2012

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

В некоторых случаях у вас есть код, который практически одинаков, или разница настолько мала, что просто не имеет значения. Это тот случай, здесь.

Где полезно поменять местами .equals (), когда у вас есть известное значение, которое не может быть null (здесь это не так) того типа, который вы используете, известен.

, например

Object o = (Integer) 123;
String s = "Hello";

o.equals(s); // the type of equals is unknown and a virtual table look might be required
s.equals(o); // the type of equals is known and the class is final.

Разница настолько мала, что я бы об этом не беспокоился.

DEVENTER (n) Решение, которое очень трудно принять, потому что от него мало что зависит, например, какой путь гулять по парку

- Дуглас Адамс и Джон Ллойд. Более глубокое значение слова "Лифф".

1 голос
/ 16 марта 2012

Если оба объекта относятся к одному и тому же типу, они должны работать одинаково. Если нет, то вы не можете заранее знать, что произойдет, но обычно это будет остановлено довольно быстро (с экземпляром или чем-то еще).

Для себя я обычно запускаю метод с ненулевой проверкой данного параметра, а затем использую attr.equals(foo.getAttr()), так как мне не нужно проверять нулевое значение в цикле. Мне кажется, это просто вопрос предпочтений.

0 голосов
/ 16 марта 2012

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

Взять, к примеру:

String s1 = null;
s1.equals("abc");
"abc".equals(s1);

Два вызова equals не эквивалентны, так как один вызовет исключение NullPointerException (первый), а другой вернет false.

Последняя форма обычно предпочтительнее сравнивать со строковыми константами именно по этой причине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...