代码之家  ›  专栏  ›  技术社区  ›  polygenelubricants

如果equals(null)抛出NullPointerException是不是一个坏主意?

  •  74
  • polygenelubricants  · 技术社区  · 15 年前

    合同 equals 关于 null ,如下所示:

    x , x.equals(null) return false .

    这很奇怪,因为如果 o1 != null o2 == null ,然后我们有:

    o1.equals(o2) // returns false
    o2.equals(o1) // throws NullPointerException
    

    事实上 o2.equals(o1) throws NullPointerException 是一件好事,因为它提醒我们程序员出错。然而,如果由于各种原因,我们只是将它切换到 o1.equals(o2)

    所以问题是:

    • o1.等于(o2) 返回false 而不是扔 NullPointerException ?
    • 如果有可能的话,我们重写合同以便 anyObject.equals(null) 总是扔

    论与 Comparable

    相反,这是 Comparable contract

    请注意 无效的 不是任何类的实例,并且 e.compareTo(null) 应该抛出一个 尽管 e.equals(null) false

    如果 适用于 compareTo ,为什么不是为了 等于 ?


    这些是 Object.equals(Object obj) 文档:

    指示是否 其他对象

    什么是物体?

    JLS 4.3.1 Objects

    类实例 或者一个数组。

    参考值(通常只是 参考文献 无效的 参考,哪一个 表示没有对象 .

    • 等于 其他对象 等于 this
    • 参考文献没有 其他对象 为了测试
    • 因此, equals(null) 空指针异常
    11 回复  |  直到 5 年前
        1
  •  104
  •   Sean Owen    8 年前

    关于这种不对称性是否不一致的问题,我想不是,我请你参考一下这个古老的禅堪:

    • 问任何一个男人他是否和下一个男人一样好,每个人都会说是的。

    这时,编译器达到了启蒙。

        2
  •  19
  •   duffymo    10 年前

    一个例外真的应该是 情况。空指针可能不是程序员错误。

        3
  •  8
  •   Angus    15 年前

    想一想.equals是如何与==相关的,而.compareTo是如何与比较运算符>,<=,<=相关的。

    如果您认为使用.equals将一个对象与null进行比较应该引发一个NPE,那么您必须说这段代码也应该抛出一个NPE:

    Object o1 = new Object();
    Object o2 = null;
    boolean b = (o1 == o2); // should throw NPE here!
    

    o1.equals(o2)和o2.equals(o1)之间的区别在于,在第一种情况下,你将一些东西与null进行比较,类似于o1==o2,而在第二种情况下, equals方法从未实际执行过

    关于.compareTo协定,将非null对象与null对象进行比较就像尝试执行以下操作:

    int j = 0;
    if(j > null) { 
       ... 
    }
    

    显然这无法编译。可以使用自动取消装箱使其编译,但在进行比较时会得到一个NPE,这与.compareTo协定一致:

    Integer i = null;
    int j = 0;
    if(j > i) { // NPE
       ... 
    }
    
        4
  •  4
  •   DaveJohnston    15 年前

    这并不是一定要回答你的问题,这只是一个例子,说明我觉得现在的行为是有用的。

    private static final String CONSTANT_STRING = "Some value";
    String text = getText();  // Whatever getText() might be, possibly returning null.
    

    if (CONSTANT_STRING.equals(text)) {
        // do something.
    }
    

    if (text != null && text.equals(CONSTANT_STRING)) {
        // do something.
    }
    

    这是一个足够的理由让这种行为保持原样吗??我不知道,但这是一个有用的副作用。

        5
  •  4
  •   arg20    11 年前

    如果将面向对象的概念考虑在内,并考虑整个发送方和接收方角色,我认为行为是方便的。在第一个例子中,你在问一个对象,他是否等于任何人。他应该说“不,我没有”。

    在第二种情况下,你没有提到任何人,所以你并没有真正问任何人。这应该引发一个异常,第一个案例不应该。

    最后一点。当代码中有错误时,应该引发空指针异常。然而,询问一个对象是否是无名小卒,不应被视为编程缺陷。我认为询问一个对象是否为空是完全可以的。如果您不控制为您提供对象的源代码怎么办?这个消息源发送给你空值。你会检查对象是否为空,然后再检查它们是否相等?如果只是比较二者,那么第二个对象是什么,那么比较将毫无例外地进行,这不是更直观吗?

    老实说,如果equals方法的主体中故意返回空指针异常,我会很生气的。Equals是用来对付任何类型的对象的,所以它不应该对接收到的内容如此挑剔。如果一个equals方法返回npe,我最不愿意想到的是它是故意这样做的。特别考虑到这是一个未经检查的异常。如果你真的提出了一个npe,一个人必须记住在调用你的方法之前总是检查null,或者更糟的是,在try/catch块中把调用围成equals(上帝,我讨厌try/catch块),但是哦,好吧。。。

        6
  •  2
  •   Rob L    15 年前

    就我个人而言,我更希望它能像现在这样表现。

    这个 NullPointerException

    空指针异常 就像你建议的那样被使用,你尝试了(有点无意义的)操作。。。

    o1.equals(o1) 其中o1=null。。。 是 空指针异常 我知道,这是一个极端的例子,但从目前的行为来看,我觉得你很容易就能看出问题出在哪里。

        7
  •  2
  •   fastcodejava    15 年前

    o1.equals(o2) 返回false,因为 o1 o2 ,这很好。在第二种情况下,它抛出 NullPointerException 因为 null 无效的 . 一般来说,这可能是编程语言的一个局限性,但我们必须接受它。

    扔也不是个好主意 你违反了 equals 方法使事情变得比它必须要复杂。

        8
  •  2
  •   Arkku    10 年前

    有很多常见的情况 null 在任何情况下都不是异常的,例如,它可以简单地表示(非例外)一个键没有值的情况,或者在其他方面代表什么都没有。因此,做 x.equals(y) 一个未知的 y 也是很常见的,而且必须经常检查 首先就是浪费精力。

    至于为什么 null.equals(y) 调用的编程错误 任何 在Java中 ,因此值得一个例外。命令 x 是的 在里面 x、 等于(y) 我们知道不是 无效的 无效的

    同时,如果两个对象都是未知的空值,那么其他代码几乎肯定需要至少检查其中一个对象,否则在不冒 NullPointerException

    因为这是它的指定方式,所以违反契约并为 论证 equals . 如果您考虑要求抛出异常的替代方法,那么 会有一个特别的情况,每次打电话给 任何潜在的 无效的

    等于 无效的 ),所以这并不是说你的论证是无效的,而是当前的规范使得编程语言更简单、更实用。

        9
  •  1
  •   Vijay Mathew Chor-ming Lung    15 年前

    if (x != null) {
        if (x.equals(null)) {
            return false;
        }
    }
    

    x 不需要 null 因为下面的定义 equals

    public boolean equals(Object obj) {
        // ...
        // If someMember is 0 this object is considered as equal to null.
        if (this.someMember == 0 and obj == null) {
             return true;
        }
        return false;
    }
    
        10
  •  1
  •   mdma    15 年前

    我认为这是为了方便,更重要的是一致性——允许null作为比较的一部分,从而避免了 null 每次检查并实现它的语义 equals 被称为。 无效的 引用在许多集合类型中都是合法的,因此可以将它们显示为比较的右侧。

    MyObject.equals(MyObjecta, MyObject b) . 然后,此方法检查一个或两个参数是否为空引用。如果我特别想排除空引用,那么我创建一个额外的方法,例如。 equalsStrict()

        11
  •  0
  •   Anton    15 年前

    这是个棘手的问题。对于向后兼容,您不能这样做。

    void m (Object o) {
     if (one.equals (o)) {}
     else if (two.equals (o)) {}
     else {}
    }
    

    现在with equals返回false else子句将被执行,但在引发异常时不会执行。

    同样null也不等于说“2”,所以返回false是非常有意义的。那么坚持一下可能更好null.等于(“b”)返回也为false:)

    但这一要求确实形成了一种奇怪的、非对称的等号关系。

        12
  •  0
  •   Dávid Horváth    5 年前

    你应该回来 false null .

    要证明这是标准,请参见' Objects.equals(Object, Object) java.util ,它只对第一个参数执行非对称null检查(在其中 equals(Object)

    public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }
    

    这也可以处理两个 无效的