When ints
is given:
List<Integer> ints = IntStream.range(0, 1000).boxed().collect(Collectors.toList());
With Java Stream API, we can reduce them
MyValue myvalue = ints
.parallelStream()
.map(x -> toMyValue(x))
.reduce((t, t2) -> t.combine(t2))
.get();
In this example, what important to me are...
toMyValue()
will be loaded at the same timeNow I want to do same processing by CompletableFuture
API.
To do map, I did:
List<CompeletableFuture<MyValue>> myValueFutures = ints
.stream()
.map(x -> CompletableFuture.supplyAsync(() -> toMyValue(x), MY_THREAD_POOL))
.collect(Collectors.toList());
And now I have no idea how to reduce List<CompeletableFuture<MyValue>> myValueFutures
to get single MyValue
.
Parallel stream provides convenient APIs but because of these problems I want not to use Stream API:
Any way to reduce CompetableFutures? one by one with out stream reduce api?
It's interesting that in your initial example you already mention a method you have combine
, while for CompletableFuture
there is a dedicated method, just for that: thenCombine
(and its two brothers thenCombineAsync
).
So considering that you have something like:
static class MyValue {
final int x;
MyValue(int x) {
this.x = x;
}
MyValue combine(MyValue v){
return new MyValue(this.x + v .x);
}
}
static MyValue toMyValue(int x) {
return new MyValue(x);
}
And:
List<CompletableFuture<Integer>> list =
IntStream.range(0, 4)
.mapToObj(x -> supplyAsync(() -> x))
.collect(Collectors.toList());
You could use one of the thenCombine
methods and achieve what you want via:
MyValue value =
list.stream()
.map(x -> x.thenApply(YourClass::toMyValue))
.reduce((left, right) -> left.thenCombine(right, MyValue::combine))
.orElse(CompletableFuture.completedFuture(new MyValue(0)))
.join();
If you want to execute the combine action in a predictable thread, you need a pool for that, or an overloaded method, like:
.reduce((left, right) -> left.thenCombineAsync(right, MyValue::combine, MY_THREAD_POOL))
Basically you need to wait for the results of all the CompletableFuture
s and combine then to obtain the result required.
There are several approaches for that, but the CompletableFuture
class provides the method allOf
that can be used for that purpose.
When I have to do with a similar problem I like to follow the Tomasz Nurkiewicz advice and perform this kind of computation in the following way.
As suggested in the article, first, let's define the following convenient method: allOf
receives arguments as varargs and doesn't return a future of aggregated results; this method will allow you to overcome those drawbacks so you can pass a Collection
as argument and return the List
of actual results instead of Void
.
private static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {
CompletableFuture<Void> allDoneFuture =
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
return allDoneFuture.thenApply(v ->
futures.stream().
map(future -> future.join()).
collect(Collectors.<T>toList())
);
}
With this handy method in place you can reduce your values with something like:
final CompletableFuture<List<MyValue>> allDone = sequence(myValueFutures);
// Please, see also for alternate approaches
// https://stackoverflow.com/questions/43489281/return-value-directly-from-completablefuture-thenaccept
final List<MyValue> myValues = allDone.join();
final Optional<MyValue> optResult = myValues.stream().
reduce((t, t2) -> t.combine(t2))
;
// Process the returned value as you consider appropriate
final MyValue result = optResult.get();
static BiFunction<Airline,Integer,Double> getTotalDelay=(airline,year)-> airline
.getFlights().stream()
.filter(flight ->flight.getScheduledDeparture().getYear()==year)
.mapToDouble(f->calcFlightDelay.apply(f)).average().orElse(0.0);
//todo: Implement the following function
static TriFunction<List<Airline>,Integer,Integer,List<String>> lowestDelaysAirlines=
(airlins,year,k)->airlins.stream()
.sorted((a1,a2)->(int)(getTotalDelay.apply(a1,year)-getTotalDelay.apply(a2,year)))
.map(al -> al.getName()).limit(k)
.collect(Collectors.toList());
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.