繁体   English   中英

迭代并调用方法列表

[英]Iterate and invoke a list of methods

假设我有2个班级:

public class Person
{
    private String name;
    private int age;
    private Contact contact;
    //getter & setter
}

public class Contact
{
    private String phone;
    private String email;
    //getter & setter
}

使用上面的类,我想创建2个Person类的实例,它们具有不同的字段值。 然后,我想将2个对象的某些字段与它们的getter函数进行比较,但是我不想比较所有字段。

例如,我想比较字段namephone ,然后将这2个getter方法存储到类似下面的列表中:

List<WhatShouldBeTheDataType> funcList = new ArrayList<>();
funcList.add(MyClass::getName);
funcList.add(MyClass::getContact::getPhone) //I know this won't work, what should be the solution?

然后遍历funcList ,将我想比较的2个对象传递给函数,如果值不相同,则将一些内容写入数据库。 这可以通过常规if...else...方式轻松完成,但是可以用Java 8方式吗?

以下是我想通过if...else...方式实现的目标:

if(person1.getName() != person2.getName())
{
    //message format basically is: "fieldName + value of object 1 + value of object 2"
    log.append("Name is different: " + person1.getName() + ", " + person2.getName());

}
if(person1.getContact.getPhone() != person2.getContact().getPhone())
{
    log.append("Phone is different: " + person1.getContact.getPhone() + ", " + person2.getContact.getPhone());
}
//other if to compare other fields

看来PersonMyClass在您的问题中指的是同一件事。

您需要一个Function<Person,String> ,因为您的函数接受一个Person实例并返回一个String

List<Function<Person,String>> funcList = new ArrayList<>();
funcList.add(Person::getName);
funcList.add(p -> p.getContact().getPhone()); 

对于第二个函数,您不能使用方法引用,但可以使用lambda表达式。

给定Person实例,您可以按以下方式应用函数:

Person instance = ...;
for (Function<Person,String> func : funcList) {
    String value = func.apply(instance);
}

尽管您可以使用函数列表(如Eran的回答中所建议),但是直接使用比较器可能更适合您的用例。

您也可以使用比较器链,然后使用compare的结果:

Comparator<Person> comparators = Comparator.comparing((Person p) -> p.getName())
        .thenComparing((Person p) -> p.getContact().getPhone());

Person p1 = null, p2 = null;
if(0 != comparators.compare(person1, person2)) {
    //p1 and p2 are different
}

甚至更简单(我认为更自然)是重写Person equals ,并检查if(!person1.equals(person2))


编辑(更新问题后):

这是一个基于函数列表的版本,通过添加字段名称列表来动态生成log内容:

List<Function<Person, String>> functions = 
        Arrays.asList(Person::getName, p -> p.getContact().getPhone());
List<String> fieldNames = Arrays.asList("Name", "Phone");

IntStream.range(0, functions.size())
        .filter(i -> functions.get(i).apply(person1)
                      .compareTo(functions.get(i).apply(person2)) != 0)
        .mapToObj(i -> String.format("%s is different: %s, %s", 
                            fieldNames.get(i),
                            functions.get(i).apply(person1), 
                            functions.get(i).apply(person2)))
        .forEach(log::append);

而是利用String已经具有可比性这一事实,并避免完全创建比较器。

完成Eran的代码:

boolean isEqual(Person person1, Person person2){
    for (Function<Person,String> function:functionList) {
        if (!function.apply(person1).equals(function.apply(person2))) return false;
    }
    return true;
}

然后使用返回的布尔值检查并更新您的数据库。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM