Sam*_*ipp 6 java grouping counting java-stream
是否可以使用Collectors.groupingBy()with Collectors.counting()来计数自定义对象的字段,而不是创建映射并随后对其进行转换。
我有一个用户列表,像这样:
public class User {
private String firstName;
private String lastName;
// some more attributes
// getters and setters
}
Run Code Online (Sandbox Code Playgroud)
我要计算所有具有相同名字和姓氏的用户。因此,我有这样的自定义对象:
public static class NameGroup {
private String firstName;
private String lastName;
private long count;
// getters and setters
}
Run Code Online (Sandbox Code Playgroud)
我可以使用以下方法收集名称组:
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());
Run Code Online (Sandbox Code Playgroud)
使用此解决方案,我必须先将用户分组到地图,然后再将其转换为我的自定义对象。是否可以直接计算所有名称,nameGroup.count以避免在列表(或映射)上重复两次并提高性能?
您可以Arrays.asList(...)通过自己构建映射而不是使用流来最大程度地减少中间对象(例如所有对象)的分配。
这依赖于 your 是可变的这一事实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
}
Run Code Online (Sandbox Code Playgroud)
完成后,您可以实现如下逻辑:
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());
Run Code Online (Sandbox Code Playgroud)
或者,如果您实际上不需要列表,则最后一行可以简化为:
Collection<NameGroup> names = map.values();
Run Code Online (Sandbox Code Playgroud)