使用流在地图上按对象的字段进行收集



假设我有一个这样的对象:

public class Person {
private String name;
private String surName;
private Set <String> domain;

创建这些对象的列表

List<Person> persons = List.of(new Person(...), new Person(...))

如何通过Stream API 实现此方法

public Map<String, List<Person>> getDomainsWithPersons(List<Person> persons) {
Map<String, List<Person>> domainsWithPersons = new HashMap<>();
for (Person person : persons) {
for (String domain : person.getDomains()) {
domainsWithPersons.computeIfAbsent(domain, p -> new ArrayList<>())
.add(person);
}
}
return domainsWithPersons;
}

因此该方法只返回一个流,类似于:

public Map<String, List<Person>> getDomainsWithPersons(List<Person> persons) {
return persons.stream()...
}

Java没有一个好的方法来使用函数式编程范式来做这样的事情——或者,至少,我认为它没有。

因此,我们可以回到旧的原型方法——迭代Person对象,并根据每个电子邮件地址的域将其添加到personsByDomain中的相应列表中。

Map<String, List<Person>> personsByDomains = new Map<>();
for (Person person : persons) {
for (String email : person.getEmails()) {  // sets are iterable, we can just do this
String domain = email.substring(email.lastIndexOf('@') + 1);
personsByDomain.putIfAbsent(domain, new ArrayList<Person>());
personsByDomain.get(domain).add(person);
}
}

想要什么并不容易。

我有一个答案给你,但是,你可以等待专家的回答。

对于一个人的每一封电子邮件,我都会创建一个新的个人对象,只是为了放一封电子邮件。这不是的最佳解决方案

public class Teste {
private static class Person {
String name;
String surName;
Set<String> emails;
public Person(String name, String surName, Set<String> emails) {
this.name = name;
this.surName = surName;
this.emails = emails;
}
@Override
public String toString() {
return String.format("Name: %s, Surname: %s, emails: %s", name, surName, emails.toString());
}
}

public static void main(String[] args) {
List<Person> people = List.of(
new Person("Matheus", "Rambo", Set.of("matheus@gmail.com", "matheus@outlook.com")),
new Person("Felipe", "Esteves", Set.of("felipe@proton.mail.com", "felipeesteves@gmail.com"))
);
people
.stream()
.flatMap(person -> {
return person.emails.stream().map(p -> {
return new Person(person.name, person.surName, Set.of(p));
});
}).collect(Collectors.groupingBy(x -> {
final String email = (String) x.emails.toArray()[0];
return email.substring(email.indexOf("@"));
}))
.forEach((key, value) -> {
System.out.printf("Domain: %s, people: %s.n", key, value.toString());
});
}
}

这是输出

Domain: @gmail.com, people: [Name: Matheus, Surname: Rambo, emails: [matheus@gmail.com], Name: Felipe, Surname: Esteves, emails: [felipeesteves@gmail.com]].
Domain: @proton.mail.com, people: [Name: Felipe, Surname: Esteves, emails: [felipe@proton.mail.com]].
Domain: @outlook.com, people: [Name: Matheus, Surname: Rambo, emails: [matheus@outlook.com]].

最新更新