是否可以将Collectors.groupingBy()
与Collectors.counting()
一起使用以计数到自定义对象的字段,而不是随后创建地图并对其进行转换。
我有一个用户列表,像这样:
public class User {
private String firstName;
private String lastName;
// some more attributes
// getters and setters
}
我要计算所有具有相同名字和姓氏的用户。因此,我有如下所示的自定义对象:
public static class NameGroup {
private String firstName;
private String lastName;
private long count;
// getters and setters
}
我可以使用以下方法收集名称组:
List<NameGroup> names = users.stream()
.collect(Collectors.groupingBy(p -> Arrays.asList(p.getFirstName(), p.getLastName()), Collectors.counting()))
.entrySet().stream()
.map(e -> new NameGroup(e.getKey().get(0), e.getKey().get(1), e.getValue()))
.collect(Collectors.toList());
使用此解决方案,我必须先将用户分组到地图,然后再将其转换为我的自定义对象。是否可以将所有名称直接计入
nameGroup.count
以避免在列表(或映射)上重复两次并提高性能? 最佳答案
您可以最小化中间对象的分配,例如所有Arrays.asList(...)
对象,都可以自己构建地图,而不要使用流式传输。
这取决于您的NameGroup
是可变的。
为了使代码更简单,让我们在NameGroup
中添加两个助手:
public static class NameGroup {
// fields here
public NameGroup(User user) {
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
}
public void incrementCount() {
this.count++;
}
// other constructors, getters and setters here
}
有了它,您可以实现如下逻辑:
Map<User, NameGroup> map = new TreeMap<>(Comparator.comparing(User::getFirstName)
.thenComparing(User::getLastName));
users.stream().forEach(user -> map.computeIfAbsent(user, NameGroup::new).incrementCount());
List<NameGroup> names = new ArrayList<>(map.values());
或者,如果您实际上不需要列表,则可以将最后一行简化为:
Collection<NameGroup> names = map.values();