13

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

查看示例:标记为@Entity通常具有Integer id字段的类。hashCode可以写成:

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

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

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

我是否需要使用try { ... } catch (Exception e)inhashCodeequals函数编写对 null 或环绕代码的检查?

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

更新我写了这样的代码:

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)

我认为如果对象处于错误状态,我可以及早发现错误而不是返回零......

4

4 回答 4

8

我会亲自检查是否为空,并使方法始终无异常返回。

虽然运行时异常通常没有记录并且可以在任何地方抛出,但我认为它们通常被equalsand抛出会很糟糕hashCode。一方面,我绝对可以理解您关于在完全填充之前放入地图的观点......但另一方面,很难真正知道equals将在哪里调用。

正如 lc 在评论中所说,如果您真的想抛出异常,最好抛出 anIllegalStateException以明确表明这是故意的,而不是让 aNullReferenceException被“默认”抛出,这看起来就像你只是没有考虑空场景。

于 2013-03-01T06:55:38.563 回答
8

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

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

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


In this particular case, you are apparently dealing with objects where the id field can be null if the object hasn't been persisted yet. This presents a tricky problem:

  • If you don't allow null for the id, then you have to be careful not to put non-persistent objects into a hash table.

  • If you do allow null for the id, then you have the problem that if you add an object to a hash table and THEN persist it, the hashcode may change leading to breakage of the hash table. So, now you need to defend against THAT ... by memoising the object's hashcode value in a transient field. And roughly the same problem occurs with equals. If equality changes when an object is persisted, then you had better not mix persisted and non-persisted keys in the same hash table.

Taking all of that into account, I'd advise to either throw that NPE, or not use the id fields in equals / hashcode.

于 2013-03-01T07:12:38.060 回答
2

为了验证对象的状态,您应该使用Bean 验证框架来确保对象的状态是有效的。

没有hashcode 和 equals 方法不应该抛出异常。

equals方法必须检查是否为空。创建对象时,创建者有责任确保对象处于有效状态,因此hashCode永远不必抛出异常。对于那个 bean 验证可以使用。国际海事组织。

更新:当您使用为您创建 bean 的 bean 框架时,您必须依赖 bean 验证。但否则它必须是Factory创建对象的责任,以确保只创建一个有效的实例

于 2013-03-01T06:53:09.310 回答
1

您永远不希望代码中出现空指针异常。从不。尤其是在您自己的代码之外大量使用的函数中。hashcode equals toString永远不应该抛出异常。

顺便说一句:你总是可以只返回 id 作为哈希码。

于 2013-03-01T06:55:35.813 回答