почему я не могу сравнить объекты исключения на предмет равенства?

#java

#java

Вопрос:

SSCCE:

 import java.util.Objects;
public class FooMain {

    private static Exception foo() {
        try {
            throw new Exception();
        } catch (Exception e) {
            return e;
        }
    }


    public static void main(String args[]) {
        final int N = 2;
        Exception es[] = new Exception[N];
        for (int i = 0 ; i < N ; i  )
            es[i] = foo();
        System.out.printf("Exceptions are equal? %bn", Objects.equals(es[0], es[1]));
        for (int i = 0 ; i < N ; i  ) {
            System.out.printf("follows exception %d:n", i);
            es[i].printStackTrace();
        }
    }
}
  

Приведенные выше результаты:

  [java] Exceptions are equal? false
 [java] follows exception 0:
 [java] follows exception 1:
 [java] java.lang.Exception
 [java]     at FooMain.foo(FooMain.java:6)
 [java]     at FooMain.main(FooMain.java:17)
 [java] java.lang.Exception
 [java]     at FooMain.foo(FooMain.java:6)
 [java]     at FooMain.main(FooMain.java:17)
  

Комментарии:

1. Какого рода равенство вы проверяете?

2. @SotiriosDelimanolis отмечает, что два исключения имеют идентичные трассировки стека (см. Мой комментарий к принятому ответу).

Ответ №1:

Класс Exception наследует свой equals() метод от Object и не переопределяет его. Вы каждый раз создаете новые экземпляры исключения, которые являются разными объектами в памяти. Несмотря на то, что их трассировки стека одинаковы, у них все еще разное распределение объектов в памяти, и с методом equals () по умолчанию они не совпадают.

Однако вы можете определить свой пользовательский класс исключений и переопределить equals() .

Комментарии:

1. Учитывая, что StackTraceElement переопределяет equals , кажется странным, что Exception также не переопределяет equals . В любом случае, я, наконец, прибегнул к итерации и сравнению по двум массивам, StackTraceElement возвращенным getStackTrace .

2. В Oracle JDK трассировка стека инициализируется лениво. Я предполагаю, что тщательное определение трассировки стека займет слишком много времени.

Ответ №2:

Вы на самом деле сравниваете их, но:

 es[0] and es[1] are not the same object
  

Из документации по объекту:

Метод equals для class Object реализует максимально различающее возможное отношение эквивалентности к объектам; то есть для любых ненулевых ссылочных значений x и y этот метод возвращает true тогда и только тогда, когда x и y ссылаются на один и тот же объект (x == y имеет значение true).

Вы могли бы сравнить их с помощью хэш-кода:

 Integer.toHexString(System.identityHashCode(es[0])) == Integer.toHexString(System.identityHashCode(es[1]))
  

И все же они не были бы одним и тем же объектом.

Я думаю, что вы хотите сравнить классы, так что это должно сработать:

 es[0].getClass().equals(es[1].getClass()) 
  

Комментарии:

1. Мне нравится предложение сравнить экземпляры класса. Я также сравнил результат toString (который по умолчанию равен «<Класс>: <сообщение>»)

Ответ №3:

Класс Exception не имеет собственной реализации метода equals. Итак, он просто проверяет ссылочную переменную. Поскольку созданы два разных объекта исключения, следовательно, разные ссылочные переменные, он показывает equals как false.

Чтобы показать больше о том, как это работает, попробуйте, как показано ниже, создать статическое исключение (не уверен в варианте использования, но просто чтобы понять, почему это не удается)

 private static Exception myStaticException = new Exception();

private static Exception foo() {
    try {
        throw myStaticException;
    } catch (Exception e) {
        return e;
    }
}
  

….

Комментарии:

1. Реализовать означает предоставить вашу собственную реализацию любого метода суперкласса. Наследование не означает, что класс имеет реализацию equals. Пожалуйста, проверьте