我在数据库中有一个 Person 表,关联的域类如下所示:
public class Person {
private String firstName;
private String secondName;
private String city;
private String country;
private int age;
private int hits;
// accessors
}
数据库表将有同一个人的多行,我需要使用 java 8 聚合每行的点击量。
一个人由以下字段唯一标识: 名字, 第二个名字, 城市, 国家
我写了下面的逻辑,它给了我预期的结果
public void generateReport(List<PersonDTO> persons) {
Map<String, Integer> personHitCount =
persons
.stream()
.collect(Collectors.groupingBy(l -> getPersonKey(l), Collectors.summingInt(Person::getHits)));
List<Person> reportRecords =
persons
.stream().collect(Collectors.toMap(l -> getPersonKey(l), Function.identity(), (o1, o2) -> o1))
.entrySet()
.stream()
.filter(e -> personHitCount.containsKey(e.getKey()))
.map(e -> transform(e.getValue(), personHitCount.get(e.getKey())))
.collect(Collectors.toList());
reportRecords.stream().forEach(System.out::println);
}
private Person transform(Person personDTO, int count) {
return new Person(
personDTO.getFirstName(),
personDTO.getSecondName(),
personDTO.getCity(),
personDTO.getCountry(),
personDTO.getAge(),
count);
}
private String getPersonKey(Person person) {
return new StringJoiner("-")
.add(person.getFirstName())
.add(person.getSecondName())
.add(person.getCity())
.add(person.getCountry())
.toString();
}
我不确定这是否是一种好的且高效的方法,因为我在人员列表上循环了两次。请您提出对此代码的任何改进或更好的方法。
您可以通过首先按 Person 而不是 String 键进行分组来改进流,然后迭代映射的条目以将每个键和值转换为具有聚合点击数的 Person。
public void generateReport2(List < Person > persons) {
List < Person > reportRecords =
persons.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(Person::getHits)))
.entrySet().stream()
.map(e - > transform(e.getKey(), e.getValue()))
.collect(Collectors.toList());
reportRecords.stream().forEach(System.out::println);
}