【发布时间】:2020-04-29 17:05:30
【问题描述】:
Java Stream 新手在这里。目前,我正在通过 book 完成有关收集器的第 6 章(使用流收集数据)。
我的对象看起来像这样。
public class Report {
private String movie;
private int movieId;
private int projections;
private int tickets;
private double income;
}
我们的想法是获得某种一般性的总结报告。基本上,HashMap<String, Double>
它将具有三个键值对。
键 1:
projections - 代表每个报告中所有预测的总和。
键 2:
tickets - 代表每个报告中所有工单的总和。
键 3:
income - 这将代表每个报告的所有收入的总和。
现在,我实际上是通过创建名为 MapCollector 的自定义收集器来完成分配的。
public class MapCollector implements Collector<Report, Map<String, Double>, Map<String, Double>>{
@SuppressWarnings("serial")
@Override
public Supplier<Map<String, Double>> supplier() {
return () -> new HashMap<String, Double>() {{
put("projections", 0.0);
put("tickets", 0.0);
put("income", 0.0);
}};
}
@Override
public BiConsumer<Map<String, Double>, Report> accumulator() {
return (map, report) ->
{
map.put("projections", map.get("projections") + report.getProjections());
map.put("tickets", map.get("tickets") + report.getTickets());
map.put("income", map.get("income") + report.getIncome());
};
}
@Override
public BinaryOperator<Map<String, Double>> combiner() {
// TODO Auto-generated method stub
return null;
}
@Override
public Function<Map<String, Double>, Map<String, Double>> finisher() {
// TODO Auto-generated method stub
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
// TODO Auto-generated method stub
return Collections.unmodifiableSet(EnumSet.of(
IDENTITY_FINISH, CONCURRENT));
}
}
所以我得到的结果是这样的:
HashMap<String, Double> result = (HashMap<String, Double>) reports.stream().collect(new MapCollector());
所以我的问题是为什么要在不创建新的 Collector 对象的情况下以不同的方式执行此操作?也许,用groupingBy 或reduce 以某种方式做到这一点?或者任何其他(更好)更具可读性的方式?
【问题讨论】:
-
当然。使用具有属性和方法的实际类,而不是 Map。然后使用docs.oracle.com/javase/8/docs/api/java/util/stream/…:
collect(Stats::new, Stats::addReport, Stats::addStats)。如果你想要一个不可变的归约,你也可以使用 reduce。原理类似。 -
感谢 JB Nizet 的回复。你的意思是这样的吗?
return (HashMap<String, Double>) reports.stream().collect(() -> new HashMap<String, Double>() { { put("projections", 0.0); put("tickets", 0.0); put("income", 0.0); }}, (map, report) -> { map.put("projections", map.get("projections") + report.getProjections()); map.put("tickets", map.get("tickets") + report.getTickets()); map.put("income", map.get("income") + report.getIncome()); }, null);该死的我不知道如何使它更具可读性。对不起先生 -
基本上,我只是替换 MapCollector 中的 lambdas 并将它们设置在这里,“内联”。我不需要组合器。所以它是空的
-
再次,定义一个类来保存这三个属性,而不是使用带有字符串键的映射。
collect(Stats::new, Stats::addReport, Stats::addStats)。这就是代码的样子。 -
首先,当您的收集器不并发时不要报告
CONCURRENT,即使用不支持并发更新的HashMap。其次,不要使用“花括号初始化”,它会创建一个捕获周围环境的子类,从而造成内存泄漏,例如MapCollector实例。第三,您可以使用map.merge("projections",report.getProjections(), Double::sum)而不是map.put("projections", map.get("projections") + report.getProjections()),同样适用于所有其他更新。组合器应该很简单,因为它看起来与累加器几乎相同。
标签: java java-stream collectors