在Java中允许和接受hashCode和equals方法中的异常吗?

时间:2013-03-01 06:49:04

标签: java exception nullpointerexception equals hashcode

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

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

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

但是defencive代码可能如下所示:

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)

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

4 个答案:

答案 0 :(得分:9)

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

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

正如lc在评论中所说的那样,如果你真的想抛出一个异常,那么抛出一个IllegalStateException就可以更清楚地表明这是故意的,而不是让NullReferenceException被抛出“默认情况下”,这使得它看起来像你没有想到空场景。

答案 1 :(得分:7)

一般来说,答案是“它取决于”。

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

  • 如果在某些情况下可以合理地预期null的实例,那么您应该处理null案例而不会抛出异常。


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

  • 如果null不允许id,则必须注意不要将非持久对象放入哈希表中。

  • 如果您对null允许id,那么您遇到的问题是,如果您将对象添加到哈希表中并且然后保留它,则hashcode可能会更改导致哈希表的破坏。所以,现在你需要通过在瞬态字段中记忆对象的哈希码值来防御这种情况。 equals出现大致相同的问题。如果在持久化对象时相等性发生变化,那么最好不要在同一个哈希表中混合使用持久密钥和非持久密钥。

考虑到所有这些因素,我建议您抛弃该NPE,或者不使用id / equals中的hashcode字段。

答案 2 :(得分:2)

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

hashcode和equals方法应不抛出例外。

equals方法必须检查无效。当创建对象时,创建者有责任确保对象处于有效状态,因此hashCode永远不会抛出异常。对于那个bean,可以使用验证。 IMO。

UPDATE :当您使用为您创建bean的bean框架时,您必须依赖bean验证。但是否则必须由Factory负责创建对象以确保仅创建有效实例

答案 3 :(得分:2)

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

BTW:你总是可以将id作为哈希码返回。