[英]Compare two objects excluding some fields - Java
我需要比较相同 class 的两个对象,不包括某些字段。
public final class Class1 {
private String a;
private String b;
private String c;
:
:
:
private String z;
private Date createdAt;
private Date updatedAt;
}
我如何才能找到上述 class 的两个对象是否相等,不包括 createdAt 和 updatedAt 值? 由于这个class中有很多字段,我不想一一比较。
请不要提供 AssertJ 的递归比较解决方案,因为 UnitTests 不需要它。
先感谢您!
如果覆盖Object::equals
和Object::hashCode
不是一个选项,我们可以使用Comparator
器 API来构造一个相应的比较器
final Comparator<Class1> comp = Comparator.comparing(Class1::getA)
.thenComparing(Class1::getB)
.thenComparing(Class1::getC)
.
.
.
.thenComparing(Class1::getZ);
不幸的是,如果不比较所有应该相等的字段,就没有办法做到这一点。
尝试重写 equals 方法,如下所示:
import java.util.Date;
import java.util.Objects;
public final class Class1 {
private String a;
private String b;
private String c;
private String z;
private Date createdAt;
private Date updatedAt;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Class1 class1 = (Class1) o;
return Objects.equals(a, class1.a) && Objects.equals(b, class1.b) && Objects.equals(c, class1.c) && Objects.equals(z, class1.z);
}
@Override
public int hashCode() {
return Objects.hash(a, b, c, z);
}
}
除了 Comparator 和hashCode()
/ equals
方法之外,您还可以使用反射。
黑名单示例:
@Retention(RetentionPolicy.RUNTIME) //
@Target(ElementType.FIELD) //on class level
public @interface IngoreForEqualCheck { /* tagging only */ }
通过在对象的 class 上使用pClass.getFields()
和/或pClass.getDeclaredFields()
,使用反射来分析要比较的对象。 这甚至可能是不同的类。
遍历所有未标记为被忽略的字段,比较值。
要从上面扩展黑名单,还需要引入白名单:还创建一个注释UseForEqualCheck
以仅检查这些字段。
为了提高速度,在分析各个 class 及其字段时,您可以创建要检查的字段的可迭代列表,而不是每次都进行反射字段分析,只需使用列表即可。
通常您会在检测到的字段值上使用equals()
。 您还可以 a) 使用另一个自定义注释标记 class,或 b) 检查字段中的任何白名单/黑名单注释,以便您可以可靠地将新方法用于嵌入/继承/委托的注释类。
与所有反射一样,在分析类的层次结构时可能会遇到麻烦,这些类在编译过程 (javac) 期间已通过注释预处理器或字节码编织进行了修改。 这主要是指 Java EE aka Jakarta,但可能发生在代码中包含幕后功能或更改运行时行为的任何地方,例如注入、面向方面的库等。
Lombok
Lombok 是 java 中最常用的库之一,它可以从您的项目中删除大量样板代码。 如果您需要详细了解它的功能和功能,请点击此处go。
实现所需内容的方法非常简单:
// Generate the equals and HashCode functions and Include only the fields that I annotate with Include
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Getter // Generate getters for each field
@Setter // Generate setters for each field
public class Class1
{
@EqualsAndHashCode.Include // Include this field
private Long identity;
private String testStr1; // This field is not annotated with Include so it will not be included in the functions.
// ... any other fields
}
龙目岛可以做的远不止这些。 有关@EqualsAndHashCode
的更多信息,请参阅此。
您始终可以使用@EqualsAndHashCode.Exclude
更快地解决您的用例:
@EqualsAndHashCode
@Getter // Generate getters for each field
@Setter // Generate setters for each field
public final class Class1 {
private String a;
private String b;
private String c;
:
:
:
private String z;
@EqualsAndHashCode.Exclude
private Date createdAt;
@EqualsAndHashCode.Exclude
private Date updatedAt;
}
@Renis1235 的 Lombok 解决方案是最简单的。 但是,如果由于某种原因在不同的上下文中,equals 可能意味着不同的东西,并且您不想更改默认的 Equals 和 Hashcode 行为,我建议您为要排除的字段分配默认值,然后使用 equals。 (假设您可以更改对象)
例如:
Class1 a = ...;
Class1 b = ...;
a.createdAt = null;
b.createdAt = null;
a.updatedAt = null;
b.updatedAt = null;
boolean isEqualExcludingTimestamps = a.equals(b);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.