假设我有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
}
使用上述类,我想创建两个Person
类的实例,它们具有不同的字段值。然后,我想将2个对象的某些字段与其getter函数进行比较,但我不想比较所有字段。
例如,我想比较字段name
和phone
,然后将这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
答案 0 :(得分:4)
Person
和MyClass
似乎在您的问题中指的是同一件事。
您需要一个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);
}
答案 1 :(得分:1)
尽管您可以使用一系列功能(如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
}
更简单(我认为更自然)是在equals
中覆盖Person
,并检查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
已经具有可比性这一事实,并且避免了完全创建比较器。
答案 2 :(得分:1)
完成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;
}
然后使用返回的布尔值检查并更新您的数据库。