我可以使用 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(...)
.)
我有一个包含以下代码的小方法:
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(...)
.)