如何用Java 8优雅实现从List<Chore>生成<Chore, Long>的出现次数统计Map
解决方法
要生成以Chore对象为键的Map<Chore, Long>,核心在于让Map把id相同的Chore识别为同一个键,具体分两种场景处理:
场景1:可以修改Chore类(推荐方案)
Java中Map判断键是否相等依赖equals()和hashCode()方法,默认的Object实现是比较对象引用,所以必须重写这两个方法,仅基于id字段判断对象相等:
import java.util.Objects; public class Chore { private String id; private String name; private String date; // 构造器、getter、setter省略 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Chore chore = (Chore) o; return Objects.equals(id, chore.id); } @Override public int hashCode() { return Objects.hash(id); } }
修改完成后,直接用Function.identity()作为分组依据,配合Collectors.counting()即可得到目标Map:
Map<Chore, Long> choreCountMap = choreList.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
此时id相同的Chore会被识别为同一个键,统计结果完全符合需求——比如id为"1"的Chore对应值3,id为"2"的对应值2。
场景2:无法修改Chore类
如果不能改动原Chore类的equals和hashCode,可以先按id分组统计次数,再将每组的第一个Chore实例作为键映射到对应次数:
Map<Chore, Long> choreCountMap = choreList.stream() // 先按id分组,得到<id, List<Chore>>结构 .collect(Collectors.groupingBy(Chore::getId)) .entrySet() .stream() // 把每个id对应的第一个Chore实例和列表大小(出现次数)转成Entry .map(entry -> new AbstractMap.SimpleEntry<>(entry.getValue().get(0), (long) entry.getValue().size())) // 收集为最终的Map .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
这种方式无需修改原类,缺点是每个分组取的是第一个Chore实例作为代表键,若需要指定实例可调整get(0)的逻辑。
内容的提问来源于stack exchange,提问作者mistakesweremade
相关产品推荐
相关产品推荐

