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

Ton*_*zza 1 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()
             );
          });
Run Code Online (Sandbox Code Playgroud)

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

谢谢,

托尼

Sto*_*ica 5

如果打印forEach很重要,那么您当前的解决方案就是好的. forEach是为副作用而设计的,您有两个副作用:向CarrierMetrics实例添加指标打印.

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

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

像这样:

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

第三个参数,即组合器,是一个虚拟的,你需要修复它.它的实现应该将两个CarrierMetrics参数合并到第一个参数中.(我不能举一个具体的例子,因为你还没有分享足够的细节CarrierMetrics以便能够看到如何做.但举一些例子,如果是List累加器,实现可能是(a1, a2) -> a1.addAll(a2).)

(最后,这个例子假设CarrierMetrics有一个无参数构造函数,供CarrierMetrics::new参考工作.如果没有这样的构造函数,你可以使用适当的lambda表达式,例如() -> new CarrierMetrics(...).)

  • 你知道组合器对顺序蒸汽来说不是可选的,对吧? (2认同)
  • @JBNizet除非记录为可选,否则它不是可选的.仅仅因为它有效并不能使它正确. (2认同)