【问题标题】:Java: howto write equals() shorterJava:如何编写更短的 equals()
【发布时间】:2013-04-25 06:38:14
【问题描述】:

当我不得不编写近 10 行代码来说出 2 Objects are equal, when their type is equal and both's attribute is equal 时,我感到很头疼。您可以很容易地看到,通过这种编写方式,行数会随着您的属性数而急剧增加。

public class Id implements Node {

        private String name;

        public Id(String name) {
                this.name = name;
        }

        public boolean equals(Object o) {
                if (o == null)
                        return false;
                if (null == (Id) o)
                        return false;
                Id i = (Id) o;
                if ((this.name != null && i.name == null) || (this.name == null && i.name != null))
                        return false;
                return (this.name == null && i.name == null) || this.name.equals(i.name);
        }

}

【问题讨论】:

  • 请参阅我的答案以正确实现 equals。将某些内容转换为错误的类型会给您一个运行时异常 (ClassCastException),而不是 null。请阅读有效的 java 以获得 fantastic 解释。
  • 顺便说一句 - 我在我的回答中链接到有效 java 的实际章节:-)。

标签: java


【解决方案1】:

Google 的 guava 库有 Objects 类和 Objects#equal 处理空值。它真的有助于让事情变得更小。以你的例子,我会写:

@Override public boolean equals(Object other) {
  if (!(other instanceof Id)) {
    return false;
  }
  Id o = (Id) other;
  return Objects.equal(this.name, o.name);
}

文档是here

另请注意,Objects#hashCodeObjects#toStringHelper 也可以帮助处理 hashCodetoString

另请参阅Effective Java 2nd Edition on how to write equals()

【讨论】:

  • 我已经更新了答案中的链接,以链接到 Effective Java 中的相关章节!现在没有理由不阅读它:-)。
  • JDK 7 也有类似的Objects.equals 方法。
【解决方案2】:

如果您使用 Eclipse,请单击“Source”->“生成 hashCode() 和 equals()”。有很多选项可以自动创建 equals()。

【讨论】:

  • 根据我的经验,生成往往会与类不同步。但这并不是一个好的代码审查无法解决的问题。我想手写的也很容易遇到同样的问题。
  • 最简单的方法。不需要关心不直接重要的事情。无论如何,生成的代码并不比我的小很多。似乎这只是Java中的正常情况......
  • 让我对这个响应说两点:(1) 不要误以为生成的代码总是正确的。 (2) 可读性是另一个问题。
  • 同意。此外 (1) 需要单元测试,例如使用您自己的代码。对于(2),我们不应该忘记,在某些情况下,生成器的结果可能会更好(就像在这种情况下),因为生成器的作者可能对这种语言/框架/无论你有更好的了解-使用它,那么你就有了。
  • @erikb - 无论如何你可能都想要单元测试。我不确定我是否遵循您所说的(2)。不知道你在说什么“更好的主意”。代码生成器不能只使用任意库为您实现功能。你需要在你的代码中有依赖(如果代码生成器在你不知道的情况下添加了一堆依赖,那将是邪恶的)。
【解决方案3】:

有一些图书馆可以为你做这件事。例如,commons-lang 有EqualsBuilder

另外,这两行似乎做同样的事情:

            if (o == null)
                    return false;
            if (null == (Id) o)
                    return false;

也许你的意思是这样的:

            if (o == null)
                    return false;
            if (this == o)
                    return true;

【讨论】:

  • 第一个 if 应该检查参数,第二个 if 应该检查类型。当我学习 Java 时,强制类型转换在不匹配的类型上返回 null。但是通过我的单元测试我已经发现,这似乎不再是这种情况了。
  • @erikb:这将导致 ClassCastException。您可以检查类是否相等,如下所示:this.getClass() == o.getClass()。子/超类虽然增加了一些皱纹。
  • @sblundy:请阅读有效的java,其中(IIRC)解释了为什么你应该使用instanceof而不是getClass()。 Josh Bloch 很好地解释了实现 equals() 的正确方法,如果你没有读过它,你几乎肯定会学到一些东西。
  • @Tom:我有。但根据我的经验,两者都有自己的位置。
  • @sblundy:java 在转换为不匹配的类型时 从不 返回 null。它总是抛出 ClassCastException。
【解决方案4】:

Project Lombok 也有一个 equalshashCode 使用 @EqualsAndHashCode 注释的生成器,其优点是与当前类/源代码同步。我不确定实施细节,但如果您需要减少麻烦,绝对值得研究。

【讨论】:

    【解决方案5】:

    一种更简单的方法(生成代码除外)可能是。

    public boolean equals(Object o) {
       return o instanceof Id 
            && (name == null ? ((Id)o).name == null : name.equals(((Id)o).name);
    }
    

    【讨论】:

    • 这并不能很好地概括(至少在可读性方面)。对于只有一个字段的情况,这只是更少的行。我的回答在这里仍然适用:return o instanceof Id && Objects.equal(name, ((Id) o).name);
    • @Tom,您的答案会更好地扩展,但需要一个额外的库(我有一个辅助方法来做同样的事情;)我相信这是对这个问题的最短完整答案。
    • +1:迄今为止最短的正确实现((null instanceof Object) == false)。值得注意的是,如果 name 永远不能为 null,则可以进一步简化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-22
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    相关资源
    最近更新 更多