我可以使用Java Stream Collector来实现此行为

时间:2017-11-26 20:07:43

标签: java java-stream collectors

我有一个包含以下代码的小方法:

final int year = getYear();
final Carrier carrier = getCarrier();
final CarrierMetrics metrics = new CarrierMetrics(carrier);
repository.getFlightStream(year)
          .filter(flight -> flight.getCarrier().equals(carrier))
          .forEach(flight -> {
             metrics.addFlight(flight);
             printf("%,10d\t%,10d\t%,10d\t%,10d\r",
                    metrics.getTotalFlights(), 
                    metrics.getTotalCancelled(), 
                    metrics.getTotalDiverted(), 
                    metrics.getAirports().size()
             );
          });

希望很明显,我正在做的是在处理流中的每个Flight时累积指标。代码确实有效,但我想知道是否有更好的(更多功能)方法来实现这种行为,可能使用收集器。任何反馈都表示赞赏。

谢谢,

托尼

2 个答案:

答案 0 :(得分:5)

如果forEach中的打印很重要, 那你现在的解决方案是好的。 forEach专为副作用而设计, 并且您有两个副作用:向CarrierMetrics实例打印添加指标。

如果forEach中的打印仅用于调试, 而不是在你的最终解决方案, 然后一个更实用的实现是将结果直接收集到CarrierMetrics实例中, 而不是首先初始化实例并手动添加forEach。 您可以使用带有3个参数的collect(...)重载:

  • Supplier<CarrierMetrics>用于创建初始CarrierMetrics实例,该实例将用作累加器
  • BiConsumer<CarrierMetrics, Flight>实例传递给累加器Flight
    • 类型Flight只是基于您共享的代码的猜测。它是流的类型(因此CarrierMetrics.addFlight方法的参数类型)
  • 在并行流的情况下组合多个累加器的BiConsumer<CarrierMetrics, CarrierMetrics>

像这样:

final int year = getYear();
final CarrierMetrics metrics = repository.getFlightStream(year)
      .filter(flight -> flight.getCarrier().equals(carrier))
      .collect(CarrierMetrics::new, CarrierMetrics::addFlight, (a1, a2) -> {});

第三个论点,即组合器,是一个虚拟的, 你需要解决这个问题。 它的实现应该将两个CarrierMetrics参数合并到第一个参数中。 (我不能举一个具体的例子,因为你还没有分享关于CarrierMetrics的足够详细信息,以便能够看到如何做。 但是要给出一些示例,如果是List累加器, 实施可以是(a1, a2) -> a1.addAll(a2)。)

(最后,此示例假定CarrierMetrics具有无参数构造函数,以使CarrierMetrics::new引用起作用。 如果没有这样的构造函数,则可以使用适当的lambda表达式,例如() -> new CarrierMetrics(...)。)

答案 1 :(得分:0)

如果CarrierMetrics公开addAll(List<Flight> flights)方法,您可以执行以下操作:

List<Flight> flights = repository.getFlightStream(year)
                    .filter(flight -> flight.getCarrier().equals(carrier))
                    .collect(Collectors.toList());
metrics.addAll(flights);