在平常的业务处理中,总是很喜欢从数据库里查询数List<T>数据,然后自己通过Map遍历去分组,现在发现Stream的分组功能非常好用,在此记录和分享下。
/**
* Stream的分组功能测试
*
* @author nanfengxiangbei
* @date 2022-04-13
*/
public class GroupingByTest {
/**
* 对集合按照单个属性分组
*/
@Test
public void testGroupingBySingleProperty1() {
List<String> items = Arrays.asList("apple", "apple", "banana", "apple", "orange", "banana", "papaya");
// 1、分组,select
Map<String, List<String>> result1 = items.stream().collect(Collectors.groupingBy(Function.identity()));
// {papaya=[papaya], orange=[orange], banana=[banana, banana], apple=[apple, apple, apple]}
System.out.println(result1);
// 2、分组、计数
Map<String, Long> result2 = items.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
// {papaya=1, orange=1, banana=2, apple=3}
System.out.println(result2);
// 3、分组、计数、排序
Map<String, Long> finalMap = new LinkedHashMap<>();
result2.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
// {apple=3, banana=2, papaya=1, orange=1}
System.out.println(finalMap);
}
/**
* 对集合按照单个属性分组
*/
@Test
public void testGroupingBySingleProperty2() {
// select age, List<people> from t_people group by age
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 = people.collect(
Collectors.groupingBy(Person::getAge)
);
// {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}]}
System.out.println(peopleByAge);
// select age, count(*) from t_people group by age
Stream<Person> people2 = Stream.of(new Person("Paul", 24, 20000),
new Person("Mark", 30, 30000),
new Person("Will", 28, 28000),
new Person("William", 28, 28000));
Map<Integer, Long> peopleByAgeCount = people2.collect(
Collectors.groupingBy(Person::getAge, Collectors.counting())
);
// {24=1, 28=2, 30=1}
System.out.println(peopleByAgeCount);
List<Person> list = Arrays.asList(new Person("Paul", 24, 20000),
new Person("Mark", 30, 30000),
new Person("Will", 28, 28000),
new Person("Will", 28, 10000),
new Person("William", 28, 28000));
// select name, sum(salary) from t_people group by name
Map<String, Long> peopleByName = list.stream().collect(
Collectors.groupingBy(Person::getName, Collectors.summingLong(Person::getSalary))
);
// {24=1, 28=2, 30=1}
System.out.println(peopleByName);
// select name,List<Person> from t_people group by name
Map<String, List<Person>> byName = list.stream().collect(
Collectors.groupingBy(Person::getName)
);
System.out.println("根据名称分组:" + byName);
// select * from t_people t where t.salary>8000
List<Person> person = list.stream().filter(x -> x.getSalary() > 8000).collect(Collectors.toList());
System.out.println("高于8000的员工信息:" + person);
// select t.name from t_people t where t.salary>8000
List<String> filterList = list.stream()
.filter(person1 -> person1.getSalary() > 8000)
.map(Person::getName)
.collect(Collectors.toList());
System.out.println("高于8000的员工姓名:" + filterList);
// select name, max(salary) from t_people group by name
Optional<Long> max = list.stream().map(Person::getSalary).max(Long::compare);
System.out.println("max(salary)=" + max);
Map<String, Person> max2 = list.stream().collect(
Collectors.toMap(Person::getName, Function.identity(), (c1, c2) -> c1.getSalary() > c2.getSalary() ? c1 : c2)
);
System.out.println("max(salary)=" + max2);
}
/**
* 对集合按照多个属性分组
*/
@Test
public void testGroupingByMultiProperty() {
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<String, List<Person>> collect = people.collect(
Collectors.groupingBy(p -> p.age + "#" + p.salary)
);
// {28#28000=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30#30000=[Person{name='Mark', age=30, salary=30000}], 24#20000=[Person{name='Paul', age=24, salary=20000}]}
System.out.println(collect);
}
/**
* 嵌套GroupingBy
*/
@Test
public void testNestedGroupingBy() {
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<String, Map<Integer, List<Person>>> collect = people.collect(
Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getAge))
);
System.out.println(collect);
}
public 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;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public long getSalary() {
return salary;
}
public void setSalary(long salary) {
this.salary = salary;
}
@Override
public String toString() {
return String.format("Person{name='%s', age=%d, salary=%d}", name, age, salary);
}
}
}