在 Java 中,hashCode 和 equals 方法中的异常是否允许和可接受?

一些由框架填充的类(如bean)。因此,您无法保证所有字段都已设置。

看个例子:标记为通常具有字段的类。 可以写成:@EntityInteger idhashCode

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

但防御性代码可能如下所示:

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

我是否需要对带有 in 和 函数的 null 或环绕代码进行写入检查?try { ... } catch (Exception e)hashCodeequals

我没有论据支持防御性编码就是这种情况,因为它隐藏了将不一致的对象放入集合并导致延迟错误。我在这个位置上错了吗?

更新我写了这样的代码:

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

一般来说,答案是“视情况而定”。

  • 如果永远看不到该字段的类的实例,则允许抛出 NPE 是合理的。NPE 表示错误;即你的非正式不变量被打破的情况。null

  • 如果在某些情况下,具有 可以合理预期的实例,那么您应该在不引发异常的情况下处理该案例。nullnull


在这种特殊情况下,您显然正在处理的对象,如果对象尚未持久化,则该字段可以为 null。这带来了一个棘手的问题:id

  • 如果不允许 ,则必须小心不要将非持久性对象放入哈希表中。nullid

  • 如果您允许 ,那么您会遇到这样的问题:如果将对象添加到哈希表并保留它,则可能会发生变化,从而导致哈希表的中断。所以,现在你需要防御那个...通过在瞬态字段中记住对象的哈希码值。与 发生大致相同的问题。如果当对象持久化时相等性发生变化,则最好不要在同一哈希表中混合使用持久化和非持久化键。nullidhashcodeequals

考虑到所有这些因素,我建议要么抛出该NPE,要么不要使用/ 中的字段。idequalshashcode


答案 2

我会亲自检查空性,并使方法始终返回,没有例外。

虽然运行时异常通常没有记录,并且可以在任何地方抛出,但我认为由 和 抛出它们通常很差。一方面,我绝对可以看到你关于在完全填充之前被放入地图中的观点......但另一方面,很难真正知道将在哪里被调用。equalshashCodeequals

正如lc在评论中所说,如果你真的想抛出一个异常,最好抛出一个,让它清楚地表明这是故意的,而不是让一个被“默认”抛出,这使得它看起来你只是没有考虑空场景。IllegalStateExceptionNullReferenceException


推荐