我从 POJO 中找到了按某些字段名称对对象进行分组的代码。下面是代码:
public class Temp { static class Person { private String name; private int age; private long salary; Person(String name, int age, long salary) { this.name = name; this.age = age; this.salary = salary; } @Override public String toString() { return String.format("Person{name='%s', age=%d, salary=%d}", name, age, salary); } } public static void main(String[] args) { Stream<Person> people = Stream.of(new Person("Paul", 24, 20000), new Person("Mark", 30, 30000), new Person("Will", 28, 28000), new Person("William", 28, 28000)); Map<Integer, List<Person>> peopleByAge; peopleByAge = people .collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList()))); System.out.println(peopleByAge); } }
输出是(这是正确的):
{24=[Person{name='Paul', age=24, salary=20000}], 28=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30=[Person{name='Mark', age=30, salary=30000}]}
但是如果我想按多个字段分组怎么办?在该 POJO 中groupingBy()实现equals()方法之后,我显然可以在方法中传递一些 POJO,但是有没有其他选项,例如我可以按给定 POJO 中的多个字段进行分组?
groupingBy()
equals()
例如,就我而言,我想按姓名和年龄分组。
你有几个选择。最简单的方法是链接您的收藏家:
Map<String, Map<Integer, List<Person>>> map = people .collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getAge));
然后要获取名为 Fred 的 18 岁人的列表,您可以使用:
map.get("Fred").get(18);
第二种选择是定义一个表示分组的类。这可以在 Person 内部。此代码使用了 ,record但在添加 JEP 359 之前,它可以很容易地成为Java 版本中的类(具有equals和hashCode定义):
record
equals
hashCode
class Person { record NameAge(String name, int age) { } public NameAge getNameAge() { return new NameAge(name, age); } }
然后你可以使用:
Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));
并搜索
map.get(new NameAge("Fred", 18));
最后,如果您不想实现自己的组记录,那么周围的许多 Java 框架都有一个pair专为此类事情设计的类。例如:apache commons pair如果您使用这些库中的一个,那么您可以将映射的键设为一对名称和年龄:
pair
Map<Pair<String, Integer>, List<Person>> map = people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));
并检索:
map.get(Pair.of("Fred", 18));
就我个人而言,我并没有真正看到通用元组有多大价值,因为记录在该语言中可用,因为记录可以更好地显示意图并且只需要很少的代码。