A Stream Collector
in plain Java that blocks until all Futures of a Stream are completed or reach a timeout.
Simply create a LenientFutureCollector
with a timeout and pass it to Stream#collect(Collector)
:
Stream.of(future1, future2, future3)
.collect(new LenientFutureCollector(Duration.ofSeconds(10)));
Executor executor = Executors.newCachedThreadPool();
List<String> results = Stream.of("1", "2", "3", "4", "5")
.map(in -> executor.submit(expensiveOperation(in))
.collect(new LenientFutureCollector(Duration.ofSeconds(1)));
// Thread is blocked until all futures are completed or the timeout is reached.
results.stream().forEach(System.out::println);
Output:
null
2
3
null
5
Note that the Collector only collects successful results (hence, "lenient"). Errors, e.g. timeouts and exceptions during execution, are ignored and mapped to null
by default. See Future 1 and 4 in the example above.
To change this behavior, an optional error mapper can be specified with the second constructor argument:
Function<Throwable, String> transformAndLog = t -> {
log.error("Something went wrong.", t);
return "ERROR";
};
new LenientFutureCollector(timeout, transformAndLog);
Be aware that:
- The order of the Stream is preserved.
- The Collector swallows
InterruptedException
s so you might want to check the interrupt flag after the Stream is closed. - Due to the lazy nature of Streams, the waiting happens when the Stream is completed (i.e. the last element of the Stream is reached). If the Stream is unbounded the collector will never trigger.