1.简介
使用Java 8流,可以很容易地根据不同的标准对对象集合进行分组。 在这篇文章中,我们将看到如何从简单的单级分组到更复杂的,涉及多个级分组的分组。
我们将使用两个类来表示我们要分组的对象:人和宠物。
人类
public class Person {
private final String name;
private final String country;
private final String city;
private final Pet pet;
public Person(String name, String country, String city, Pet pet) {
this.name = name;
this.country = country;
this.city = city;
this.pet = pet;
}
public String getName() {
return name;
}
public String getCountry() {
return country;
}
public String getCity() {
return city;
}
public Pet getPet() {
return pet;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", country='" + country + '\'' +
", city='" + city + '\'' +
'}';
}
}
宠物课
public class Pet {
private final String name;
private final int age;
public Pet(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在主要方法中,我们创建将在以下各节中使用的集合。
public static void main(String[] args) {
Person person1 = new Person("John", "USA", "NYC", new Pet("Max", 5));
Person person2 = new Person("Steve", "UK", "London", new Pet("Lucy", 8));
Person person3 = new Person("Anna", "USA", "NYC", new Pet("Buddy", 12));
Person person4 = new Person("Mike", "USA", "Chicago", new Pet("Duke", 10));
List<Person> persons = Arrays.asList(person1, person2, person3, person4);
- 您可以在此处查看源代码。
2.单层分组
最简单的分组形式是单级分组。 在此示例中,我们将按其国家/地区对集合中的所有人员进行分组:
public void singleLevelGrouping(List<Person> persons) {
final Map<String, List<Person>> personsByCountry = persons.stream().collect(groupingBy(Person::getCountry));
System.out.println("Persons in USA: " + personsByCountry.get("USA"));
}
如果我们查看地图,就会看到每个国家如何包含其公民列表:
结果显示居住在指定国家/地区的人:
Persons in USA: [Person{name='John', country='USA', city='New York'}, Person{name='Anna', country='USA', city='New York'}, Person{name='Mike', country='USA', city='Chicago'}]
3.两级分组
在此示例中,我们将不仅按国家/地区分组,还按城市分组。 为此,我们需要实现两级分组。 我们将按国家对人员进行分组,对于每个国家,我们将按其居住城市对人员进行分组。
为了允许多级分组,类Collectors中的groupingBy方法支持附加的Collector作为第二个参数:
public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream)
让我们使用此方法来实现我们的两级分组:
public void twoLevelGrouping(List<Person> persons) {
final Map<String, Map<String, List<Person>>> personsByCountryAndCity = persons.stream().collect(
groupingBy(Person::getCountry,
groupingBy(Person::getCity)
)
);
System.out.println("Persons living in London: " + personsByCountryAndCity.get("UK").get("London").size());
}
如果我们调试执行,我们将看到人员的分布情况:
4.三级分组
在最后一个示例中,我们将更进一步,并按国家/地区,城市和宠物的名字对人进行分组。 为了便于阅读,我将其分为两种方法:
public void threeLevelGrouping(List<Person> persons) {
final Map<String, Map<String, Map<String, List<Person>>>> personsByCountryCityAndPetName = persons.stream().collect(
groupingBy(Person::getCountry,
groupByCityAndPetName()
)
);
System.out.println("Persons whose pet is named 'Max' and live in NY: " +
personsByCountryCityAndPetName.get("USA").get("NYC").get("Max").size());
}
private Collector<Person, ?, Map<String, Map<String, List<Person>>>> groupByCityAndPetName() {
return groupingBy(Person::getCity, groupingBy(p -> p.getPet().getName()));
}
现在我们有了三个嵌套的地图,其中包含每个人员列表:
5.结论
Java 8 Collectors API为我们提供了一种对集合进行分组的简便方法。 通过嵌套收集器,我们可以添加不同的组层以实现多级分组。
翻译自: https://www.javacodegeeks.com/2016/03/multi-level-grouping-streams.html