Являются ли исключения в методах hashCode и equals допустимыми и приемлемыми в Java?

Некоторые классы, заполненные фреймворками (например, beans). Поэтому вы не можете гарантировать, что все поля установлены.

Посмотрите на пример: классы, помеченные как @Entity, обычно имеют поле Integer id. hashCode может быть записана как:

public int hashCode() {
    return id.hashCode();
}

но defencive code может выглядеть так:

public int hashCode() {
    return (id != null) ? id.hashCode() : 0;
}

Нужно ли писать записи для нулевого или объемного кода с try { ... } catch (Exception e) в hashCode и equals функциями?

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

ОБНОВЛЕНИЕ Я написал такой код:

import java.util.*;

class ExceptionInHashcode {

    String name;

    ExceptionInHashcode() { }
    ExceptionInHashcode(String name) { this.name = name; }

    public int hashCode() {
        // throw new IllegalStateException("xxx");
        return this.name.hashCode();
    }

    public static void main(String args[]) {
        Hashtable list = new Hashtable();
        list.put(new ExceptionInHashcode("ok"), 1);
        list.put(new ExceptionInHashcode(), 2); // fail
        System.out.println("list.size(): " + list.size());
    }
}

и запустите его:

java -classpath . ExceptionInHashcode
Exception in thread "main" java.lang.NullPointerException
        at ExceptionInHashcode.hashCode(ExceptionInHashcode.java:12)
        at java.util.Hashtable.hash(Hashtable.java:262)
        at java.util.Hashtable.put(Hashtable.java:547)
        at ExceptionInHashcode.main(ExceptionInHashcode.java:18)

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

Ответ 1

В общем, ответ "зависит".

  • Если вы никогда не увидите экземпляры класса с null для этого поля, тогда разумно разрешить выброс NPE. NPE указывает на ошибку; то есть ситуация, когда ваш неформальный инвариант нарушен.

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


В этом конкретном случае вы, по-видимому, имеете дело с объектами, где поле id может быть пустым, если объект еще не был сохранен. Это представляет собой сложную проблему:

  • Если вы не разрешаете null для id, тогда вы должны быть осторожны, чтобы не помещать нестационарные объекты в хеш-таблицу.

  • Если вы разрешаете null для id, тогда у вас есть проблема, что если вы добавите объект в хеш-таблицу, а THEN сохраните его, то значение hashcode может измениться, что приведет к поломке хеш-таблица. Итак, теперь вам нужно защититься от THAT... путем запоминания значения хэш-кода объекта в переходном поле. И примерно такая же проблема возникает с equals. Если равенство изменяется, когда объект сохраняется, то вам лучше не смешивать сохраненные и неизменяемые ключи в одной и той же хеш-таблице.

Учитывая все это, я бы посоветовал либо выбросить этот NPE, либо не использовать поля id в equals/hashcode.

Ответ 2

Я лично проверил бы недействительность и всегда возвращал методы без исключений.

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

Как говорит lc в комментариях, если вы действительно хотите выбросить исключение, было бы гораздо лучше бросить IllegalStateException, чтобы было ясно, что это было преднамеренно, чем позволить a NullReferenceException быть выброшенным "default", что делает его похожим на то, что вы просто не думали о нулевом сценарии.

Ответ 3

Для проверки состояния объекта вы должны использовать Bean структуру проверки, чтобы убедиться, что состояние объекта действительно.

Нет hashcode и equals метод должен не бросать Исключения.

equals метод должен иметь проверку недействительности. И когда объект создается, разработчики должны быть уверены, что объект находится в правильном состоянии, поэтому hashCode никогда не придется бросать исключение. Для этого можно использовать валидацию bean. ИМО.

UPDATE. Поскольку вы используете фреймворки bean, которые создают для вас beans, вы должны полагаться на проверку bean. Но в противном случае он ДОЛЖЕН быть ответственным за Factory, который создает объект, чтобы убедиться, что создан только действительный экземпляр.

Ответ 4

Вы никогда не хотите исключать нулевой указатель в своем коде. Никогда. Особенно в функциях, сильно используемых вне вашего собственного кода. hashcode equals toString никогда не должен генерировать исключения.

BTW: вы всегда можете просто вернуть id в качестве хэш-кода.