Почему реализация equals(), созданная Eclipse, проверяет значение null перед проверкой типа (instanceof)?

Я регулярно использовал инструменты генерации кода Eclipse (Source/Generate hashCode() и equals()...), чтобы создать реализацию equals() для простых классов POJO. Если я выбираю "Использовать instanceof для сравнения типов", это приводит к реализации equals(), аналогичной следующей:

  @Override
  public boolean equals(Object obj) {
      if (this == obj) {
          return true;
      }
      if (obj == null) {
          return false;
      }
      if (!(obj instanceof MyClass)) {
          return false;
      }
      MyClass other = (MyClass) obj;
      // check the relevant fields for equality
  }

Сегодня коллега отметил, что второй оператор if вообще не нужен, поскольку проверка типа instanceof вернет false всякий раз, когда obj равно null. (См. вопрос 3328138.)

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

(Также вопрос 7570764 может дать подсказку: если мы используем сравнение getClass() для проверки типов, то instanceof, obj.getClass() не является нулевым. шаблон кода просто недостаточно умен, чтобы опустить нулевую проверку, если мы используем instanceof.)

EDIT: Драган заметил в своем ответе, что проверка типа instanceof не является настройкой по умолчанию в Eclipse, поэтому я отредактировал это без вопросов. Но это ничего не меняет.

Также не рекомендуется использовать getClass() или (даже лучше!) другую среду IDE. Это не вопрос, который не отвечает на вопрос. Я не просил совета относительно того, как написать реализацию equals(), использовать ли instanceof или getClass() и т.д.

Вопрос примерно таков: это незначительная ошибка в Eclipse? И если это не так, то почему это квалифицируется как функция?

Ответ 1

Это необязательно, потому что instanceof имеет встроенную нулевую проверку. Но instanceof намного больше, чем просто foo == null. Это полная инструкция по подготовке проверки класса, выполняющая ненужную работу до того, как будет выполнена нулевая проверка. (подробнее см. http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.instanceof)

Таким образом, отдельная проверка нуля может быть улучшением производительности. Быстрое измерение и неудивительно, что foo == null быстрее, чем nullcheck с экземпляром.

Но обычно у вас нет тонны нулей в equals(), оставляя вас с дублирующимся ненужным nullcheck в большинстве случаев... что, вероятно, съедет любое улучшение, сделанное при нулевых сравнениях.

Мой вывод: Это не нужно.

Код, используемый для тестирования полноты (не забудьте использовать -Djava.compiler = NONE else, вы будете только измерять мощность java):

public class InstanceOfTest {
    public static void main(String[] args) {
        Object nullObject = null;

        long start = System.nanoTime();         
        for(int i = Integer.MAX_VALUE; i > 0; i--) {
            if (nullObject instanceof InstanceOfTest) {}
        }
        long timeused = System.nanoTime() - start;  

        long start2 = System.nanoTime();
        for(int i = Integer.MAX_VALUE; i > 0; i--) {
            if (nullObject == null) {}
        }
        long timeused2 = System.nanoTime() - start2;

        System.out.println("instanceof");
        System.out.println(timeused);       
        System.out.println("nullcheck");
        System.out.println(timeused2);
    }
}

Ответ 2

В самом деле, это не нужно, и это ошибка авторов шаблона Eclipse. И это не первый; Я нашел там больше мелких ошибок. Например, генерация метода toString(), когда я хочу опустить значения null:

public class A {
    private Integer a;
    private Integer b;

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("A [");
        if (a != null)
            builder.append("a=").append(a).append(", ");
        if (b != null)
            builder.append("b=").append(b);
        builder.append("]");
        return builder.toString();
    }
}

Если a не null и b есть, перед закрытием ] будет добавлена ​​дополнительная запятая.

Итак, в отношении вашего утверждения: "Теперь я думаю, что люди, которые пишут шаблоны кода для Eclipse JDT, тоже заслуживают их соли". Я предполагаю, что это так, но это не помешает им уделять больше внимания этим крошечные несоответствия.:)