我可以使用 Java 流收集器来实现此行为吗

Can I use a Java Stream Collector to implement this behavior

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

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()
             );
          });

希望很明显我正在做的是在处理流中的每个航班时累积指标。该代码确实有效,但我想知道是否有更好(功能更强大)的方法来实现此行为,可能使用收集器。感谢任何反馈。

谢谢,

-托尼

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

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

如果 forEach 中的印刷很重要, 那么您当前的解决方案就很好。 forEach 专为副作用而设计, 并且您有两个副作用:将指标添加到 CarrierMetrics 实例 打印。

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

  • A Supplier<CarrierMetrics> 创建初始 CarrierMetrics 实例,它将用作 累加器
  • A 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 的细节来了解如何做。 但是举 some 的例子,在 List 累加器的情况下, 实现可以是 (a1, a2) -> a1.addAll(a2).)

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