简体   繁体   中英

Iterate and invoke a list of methods

Let say I have 2 classes:

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
}

With the classes above, I want to create 2 instances of Person class, with different field value. Then I want to compare some fields of 2 objects with their getter function, but I don't want to compare all fields.

For example, I want to compare the field name and phone , then I will store this 2 getter method to a list like something below:

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?

then loop through the funcList , pass the 2 objects I want to compare into the function, if the value not same, write something into the database. This can be easily done with ordinary if...else... way, but is it possible to do in Java 8 way?

Below is what I want to achieve in if...else... way:

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

It looks like Person and MyClass refer to the same thing in your question.

You need a Function<Person,String> , since your functions accept a Person instance and return a String :

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

For the second function, you can't use a method reference, but you can use a lambda expression instead.

Given an instance of Person , you can apply your functions as follows:

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

Although you can use a list of functions (as suggested in Eran's answer), using comparators directly is probably more appropriate for your use case.

You can alternatively use a chain of comparators, and then use the result of 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
}

Even simpler (and more natural, in my opinion), is overriding equals in Person , and checking if(!person1.equals(person2))


Edit (after update of the question):

Here's a version built on a function list, dynamically generating the log content by adding a field name list:

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);

This rather takes advantage of the fact that String is already comparable, and avoids creating comparators altogether.

to complete Eran's code:

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

then use the returned boolean to check and update your database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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