含大量字段的类重写equals()方法的实用替代方案
绝对懂这种写一堆equals校验的痛苦!20个字段手动写不仅容易漏写、写错,后期改字段的时候还容易忘同步equals和hashCode,简直是维护噩梦。分享几个我在生产环境里亲测好用的替代方案:
这是我最常用的方案,几乎能解决90%以上的equals冗余问题。只要给你的类加上@EqualsAndHashCode注解,Lombok会自动帮你生成覆盖所有字段的equals和hashCode方法,还能灵活处理各种特殊需求:
import lombok.EqualsAndHashCode; @EqualsAndHashCode public class YourBigClass { private HashMap<K, V> dataMember1; private String dataMember2; private CustomClass dataMember3; // ... 剩下的17个数据成员 }
如果有不需要参与比较的字段,直接给该字段加@EqualsAndHashCode.Exclude:
@EqualsAndHashCode.Exclude private transient String tempField; // 临时字段不需要参与equals
如果只需要指定部分字段参与比较,可以用of参数:
@EqualsAndHashCode(of = {"dataMember1", "dataMember2"}) public class YourBigClass { // ... 类字段 }
另外如果你的类继承了父类,需要把父类的字段也纳入比较,加上callSuper = true即可:
@EqualsAndHashCode(callSuper = true) public class YourBigClass extends ParentClass { // ... 类字段 }
如果你不想引入Lombok(比如团队有规范限制),Apache Commons Lang的EqualsBuilder是个不错的替代。它把冗长的&&链式调用变成了更清晰的方法调用,还自动处理null判断:
import org.apache.commons.lang3.builder.EqualsBuilder; @Override public boolean equals(Object o) { if (this == o) return true; // 先判断引用相等 if (o == null || getClass() != o.getClass()) return false; // 类型校验 YourBigClass that = (YourBigClass) o; return new EqualsBuilder() .append(dataMember1, that.dataMember1) .append(dataMember2, that.dataMember2) .append(dataMember3, that.dataMember3) // ... 依次添加剩下的所有字段 .isEquals(); }
这个方案比手动写一堆Objects.equals(a, b) && Objects.equals(c, d)可读性高很多,也不容易因为漏写括号导致逻辑错误。
如果你的类只是单纯的数据容器,没有任何业务逻辑方法,那么Java 16引入的Record类是最优解。Record会自动为所有组件生成equals、hashCode和toString方法,完全不需要手动编写:
public record YourBigRecord( HashMap<K, V> dataMember1, String dataMember2, CustomClass dataMember3, // ... 剩下的17个数据成员 ) {}
Record的equals方法会自动基于所有组件进行比较,对于集合(比如HashMap)和自定义类,只要它们自己正确实现了equals,就能得到正确的比较结果。而且Record默认是不可变的,非常适合作为DTO或者数据传输对象。
不管用哪种方案,都要确保:
- 所有自定义类型的字段(比如你的
CustomClass)自己正确重写了equals和hashCode方法,否则上层的equals比较会失效。 - 如果用Lombok,记得在IDE中安装Lombok插件,避免出现编译报错或者代码提示异常。
内容的提问来源于stack exchange,提问作者Kris

