比较两个对象的不同属性集

问题描述

我有一个数据类。字段可以是集合、原语、引用等。我必须检查这个类的两个实例的相等性。通常我们会为此目的重写 equals 方法。但是用例是这样的,要比较的属性可能会有所不同。

所以说,A 类有属性

int name:
int age:
List<String> hobbies;

在一次调用中,我可能必须根据姓名、年龄检查相等性,而对于另一次调用,我可能必须检查姓名、爱好的相等性

实现这一目标的最佳做法是什么?

解决方法

假设您想总是通过 2 个属性进行比较,那么在 Java 8 中最好使用一等函数。

private boolean equalNameAndAge(A a1,A a2) {
    return compareByTwoParameters(a1,a2,A::getName,A::getAge);
}

private boolean equalNameAndHobbies(A a1,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;
}
,

anyMatch

您可以使用 Stream API 解决这个问题,使用 anyMatch,您的规则基本上被定义为 Predicate

例如检查是否有人是 20 岁:

List<Person> persons = ...

boolean doesAnyMatch = persons.stream()
    .anyMatch(p -> p.getAge() == 20);

您当然也可以通过与现有项目进行比较的方式来设置规则,更多地模仿 equals

p -> p.getAge() == otherPerson.getAge()

Predicate

您可以在其他地方设置所有规则,作为 Predicate 并使用它们。例如:

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 替换为 filterfindAny 的组合以接收实际匹配,即 Person,而不仅仅是 boolean

Person matchingPerson = persons.stream()
    .filter(rule)
    .findAny();

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...