比较两个对象的不同属性集
Comparing two objects for varying set of properties
我有一个数据class。字段可以是集合、基元、引用等。我必须检查此 class 的两个实例是否相等。通常我们为此目的重写 equals 方法。但是用例是这样的,要比较的属性可能会有所不同。
所以说,class A 有属性:
int name:
int age:
List<String> hobbies;
在一次调用中,我可能必须根据姓名、年龄检查是否相等,而对于另一次调用,我可能必须检查姓名、爱好是否相等。
实现此目标的最佳做法是什么?
anyMatch
您可以使用 Stream API 解决此问题,使用 anyMatch
,您的规则基本上被定义为 Predicate
s。
例如检查是否有 20
岁的人:
List<Person> persons = ...
boolean doesAnyMatch = persons.stream()
.anyMatch(p -> p.getAge() == 20);
您当然也可以将规则设置为与现有项目进行比较的方式,稍微模仿 equals
:
p -> p.getAge() == otherPerson.getAge()
Predicate
您可以在其他地方设置所有规则,如 Predicate
s 然后使用它们。例如:
List<Predicate<Person>> rules = List.of(
p -> p.getAge() == 20,
p -> p.getName().equals("John"),
p -> p.getAge() > 18,
p -> p.getName().length() > 10 && p.getAge() < 50
);
然后可以在某种循环中使用它们,无论您需要什么:
for (Predicate rule : rules) {
boolean doesAnyMatch = persons.stream()
.anyMatch(rule);
...
}
findAny
您可以将 anyMatch
替换为 filter
和 findAny
的组合以获得实际匹配,即 Person
,而不仅仅是 boolean
:
Person matchingPerson = persons.stream()
.filter(rule)
.findAny();
假设您想始终通过 2 个属性进行比较,那么对于 Java8,最好先使用 class 函数。
private boolean equalNameAndAge(A a1, A a2) {
return compareByTwoParameters(a1, a2, A::getName, A::getAge);
}
private boolean equalNameAndHobbies(A a1, A a2) {
return compareByTwoParameters(a1, a2, A::getName, A::getHobbies);
}
private boolean compareByTwoParameters(A a1, A a2, Function<A, ?>... functions) {
if (a1 == null || a2 == null) {
return a1 == a2;
}
for (Function<A, ?> function : functions) {
if (!Objects.equals(function.apply(a1), function.apply(a2))) {
return false;
}
}
return true;
}
我有一个数据class。字段可以是集合、基元、引用等。我必须检查此 class 的两个实例是否相等。通常我们为此目的重写 equals 方法。但是用例是这样的,要比较的属性可能会有所不同。
所以说,class A 有属性:
int name:
int age:
List<String> hobbies;
在一次调用中,我可能必须根据姓名、年龄检查是否相等,而对于另一次调用,我可能必须检查姓名、爱好是否相等。
实现此目标的最佳做法是什么?
anyMatch
您可以使用 Stream API 解决此问题,使用 anyMatch
,您的规则基本上被定义为 Predicate
s。
例如检查是否有 20
岁的人:
List<Person> persons = ...
boolean doesAnyMatch = persons.stream()
.anyMatch(p -> p.getAge() == 20);
您当然也可以将规则设置为与现有项目进行比较的方式,稍微模仿 equals
:
p -> p.getAge() == otherPerson.getAge()
Predicate
您可以在其他地方设置所有规则,如 Predicate
s 然后使用它们。例如:
List<Predicate<Person>> rules = List.of(
p -> p.getAge() == 20,
p -> p.getName().equals("John"),
p -> p.getAge() > 18,
p -> p.getName().length() > 10 && p.getAge() < 50
);
然后可以在某种循环中使用它们,无论您需要什么:
for (Predicate rule : rules) {
boolean doesAnyMatch = persons.stream()
.anyMatch(rule);
...
}
findAny
您可以将 anyMatch
替换为 filter
和 findAny
的组合以获得实际匹配,即 Person
,而不仅仅是 boolean
:
Person matchingPerson = persons.stream()
.filter(rule)
.findAny();
假设您想始终通过 2 个属性进行比较,那么对于 Java8,最好先使用 class 函数。
private boolean equalNameAndAge(A a1, A a2) {
return compareByTwoParameters(a1, a2, A::getName, A::getAge);
}
private boolean equalNameAndHobbies(A a1, A a2) {
return compareByTwoParameters(a1, a2, A::getName, A::getHobbies);
}
private boolean compareByTwoParameters(A a1, A a2, Function<A, ?>... functions) {
if (a1 == null || a2 == null) {
return a1 == a2;
}
for (Function<A, ?> function : functions) {
if (!Objects.equals(function.apply(a1), function.apply(a2))) {
return false;
}
}
return true;
}