本文已参与「新人创作礼」活动,一起开启掘金创作之路。
java8 分组和排序
文本介绍了java8 lambada表达式用于多字段排序和分组的使用场景
1 拼接分组key
Map<String, Long> countMap = records.stream()
.collect(Collectors.groupingBy(o -> o.getProductType() + "_" + o.getCountry(), Collectors.counting()));
2 多字段分组 链式收集器 chain collectors
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}]
}
Map<String, Map<Integer, List<Person>>> map = people.collect(Collectors.groupingBy(Person::getName,
Collectors.groupingBy(Person::getAge));
//获取结果2级map map.get("Fred").get(18);
//超过2级的嵌套分组 https://xpadro.com/2016/02/multi-level-grouping-with-streams.html
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()));
}
}
3 在jdk14 后可以使用record
第三种选择是定义一个代表分组的类。这可以在Person内部,重写必要的hashcode 和equase
class Person {
public static class NameAge {
public NameAge(String name, int age) {
...
}
// must implement equals and hash function
}
public NameAge getNameAge() {
return new NameAge(name, age);
}
}
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));
4 利用函数来生成组合key
Function<Person, List<Object>> compositeKey = personRecord ->
Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());
Map<Object, List<Person>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
5 利用LIst 或数组 Ararys.asList() 【推荐使用】
Function<String, List> classifier = (item) -> List.of(
item.getFieldA(),
item.getFieldB(),
Optional.ofNullable(item.getFieldC())
)
);
Map<List, List<Item>> grouped = items.stream()
.collect(Collectors.groupingBy(classifier));
Map<Object, Long> M = LON.stream().collect(
Collectors.groupingBy(p
-> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
Collectors.counting()));
6 多字段排序 【重要】
//参考 https://howtodoinjava.com/java8/sort-stream-multiple-fields/
//first name comparator
Comparator<Employee> compareByFirstName = Comparator.comparing( Employee::getFirstName );
//last name comparator
Comparator<Employee> compareByLastName = Comparator.comparing( Employee::getLastName );
//Compare by first name and then last name (multiple fields)
Comparator<Employee> compareByFullName = compareByFirstName.thenComparing(compareByLastName);
//Using Comparator - pseudo code
list.stream().sorted( comparator ).collect();
7 参考文档
stackoverflow.com/questions/2…
www.baeldung.com/java-groupi… 【经典】
grokonez.com/java/java-8… 【经典】