使用 Java8 比较两种不同类型的列表

comparing two different type of List using Java8

class Person{

private String name;
private String address;
private int id;
private int uniqueIdentificationNumber;

}


class Company{

private String name;
private String address;
private int id;
private int uniqueIdentificationNumber;
private String company;
}


class Test{

public static void main(String[] args)
{
     List<Person> persons = new ArrayList<>();
      Person p1 = new Person();
      p1.setName("ABC");
      p1.setAddress("US");
      p1.setId(1);
      p1.setUniqueIdentificationNumber(11);
     
      Person p2 = new Person();
      p2.setName("PQR");
      p2.setAddress("US");
      p2.setId(2);
      p2.setUniqueIdentificationNumber(22);
     
      persons.add(p1);
      persons.add(p2);  

     List<Company> companies = new ArrayList<>();
     
     Company c1 = new Comapny();
      c1.setName("ABC");
      c1.setAddress("US");
      c1.setId(3);
      c1.setUniqueIdentificationNumber(44);
      c1.setCompany("C1")

     Company c2 = new Comapny();
      c2.setName("ABC");
      c2.setAddress("US");
      c2.setId(1);
      c2.setUniqueIdentificationNumber(11);
      c2.setCompany("C2");

      companies.add(c1);
      companies.add(c2)

}
}

我想将两种不同对象类型的列表(公司和个人)与 Java8 流 API 和 return 客户进行比较与 Id 和 setUniqueIdentificationNumber 匹配的对象。即在这种情况下它应该重新调整 c2.

谁能帮忙解决这个问题

不清楚 PersonCompany 中的 uniqueIdentificationNumber 是如何关联的。值得refine这些classes来更好地表示它们之间的关系(也许公司可以参考客户名单)。并且不要过度使用 setter,如果 id 是唯一的,则无需允许更改它。

尽管由于您的 class 设计存在缺陷,尚不清楚这些值是如何关联的,但在技术上是可行的。

return the customer object which is matching with Id

为此,您需要创建两个 映射,将这些 标识符公司。然后在其中一个 mapskeys 上创建一个流,并检查每个 key 是否包含在另一个 map 中。然后检索过滤键的 Person 对象并将结果收集到列表中。

    Map<Integer, Person> personById =
            persons.stream()
                    .collect(Collectors.toMap(Person::getUniqueIdentificationNumber,
                                              Function.identity()));
    Map<Integer, Company> companyById =
            companies.stream()
                     .collect(Collectors.toMap(Company::getUniqueIdentificationNumber,
                                               Function.identity()));

    List<Person> customers =
            personById.keySet().stream()
                    .filter(companyById::containsKey) // checking whether id is present in the company map
                    .map(personById::get) // retrieving customers
                    .collect(Collectors.toList());

更新

让我重新描述一下问题。

有两个不相关的 classes AB。两个 class 都有 两个 int 类型的字段 ,比方说 val1val2(也许还有几个字段,但我们对它们不感兴趣)。

我们有对象列表 A 和对象列表 B。目标是找到一个对象 A,其中存在一个对象 Bval1val2 具有相同的值(为了简单起见,我建议坚持这个例子)。

有两种方法可用于此目的:

  • 创建一个具有两个字段 val1val2 的辅助 class,并将 AB 的每个实例与此 [= 的实例相关联105=];
  • 创建一个嵌套映射Map<Integer, Map<Integer, *targetClass*>>,这个解决方案比较复杂且不太灵活,如果您需要按三个、四个等字段比较对象,代码将很快变得难以理解。

所以我会坚持使用第一种方法。我们需要声明 ValueHolder class 两个字段,并根据这些字段实现 equals/hashCode 合约。对于 Java 16 及以上我们可以利用 record 并利用 equals(), hashCode, 编译器提供的getters。带有记录的选项将如下所示:

public record ValueHolder(int val1, int val2) {} // equals/hashCode, constructor and getters provided by the compiler

AB

public class A {
    private int val1;
    private int val2;

    // constructor and getters
}

public class B {
    private int val1;
    private int val2;

    // constructor and getters
}

以及接受两个列表的方法:List<A>List<B>,以及 return 结果为 Optional<A>。因为匹配元素可能存在也可能不存在,在这种情况下 return 一个可选对象是一个很好的做法,而不是 returning null 以防找不到结果。它提供了更大的灵活性,而这正是设计可选选项的原因。

public Optional<A> getMatchingItem(List<A> listA, List<B> listB) {

    Map<ValueHolder, A> aByValue = listA.stream()
            .collect(Collectors.toMap(a -> new ValueHolder(a.getVal1(), a.getVal2()),
                    Function.identity()));

    Map<ValueHolder, B> bByValue = listB.stream()
            .collect(Collectors.toMap(b -> new ValueHolder(b.getVal1(), b.getVal2()),
                    Function.identity()));

    return aByValue.keySet().stream()
            .filter(bByValue::containsKey)
            .findFirst()
            .map(aByValue::get);
}