【问题标题】:Iterate and invoke a list of methods迭代并调用方法列表
【发布时间】:2018-08-07 07:24:37
【问题描述】:

假设我有 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,然后我会将这两个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

【问题讨论】:

    标签: java arraylist java-8


    【解决方案1】:

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

    您需要一个Function&lt;Person,String&gt;,因为您的函数接受一个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);
    }
    

    【讨论】:

    • 谢谢你的帮助,但是我问题的后半部分呢?这是如何将 2 个对象与存储在 funcList 中的函数进行比较?
    • @Newbie 您可以将这些函数传递给Comparators.comparing 以获取Comprator&lt;Person&gt; 的实例。然后你可以直接使用Comparatorcompare方法,或者将Comparator传递给其他方法(例如传递给Collections.sort(),对List&lt;Person&gt;进行排序)。
    【解决方案2】:

    完成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;
    }
    

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

    【讨论】:

      【解决方案3】:

      虽然您可以使用函数列表(如 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 已经具有可比性这一事实,并且完全避免创建比较器。

      【讨论】:

      • 嗨,谢谢你分享你的想法,但我想对每个数据不匹配做一个任务,请参阅我更新的问题。
      • @Newbie 已编辑。这稍微改变了它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-25
      • 2019-12-04
      • 1970-01-01
      • 1970-01-01
      • 2016-05-14
      • 1970-01-01
      • 2016-08-29
      相关资源
      最近更新 更多