Normally with a CompletableFuture I would call thenApply or some other method on it to do something as soon as the result is available. However, I now have a situation where I want to process results until I receive a positive result and then ignore all further results.
If I just wanted to take the first available result I could use CompletableFuture.anyOf (although I hate having to convert a list to an array just to call anyOf). But that's not what I want. I want to take the first result and if it does not have a desirable result then I want to process the second available result and so on until I get a desirable result.
Here's a simple example which goes through all results and returns the first value it finds which is greater than 9. (Note that this is not my real task. This is just a simple example.)
public Integer findFirstGt9(List<CompletableFuture<Integer>> results) {
for(CompletableFuture<Integer> result : results) {
Integer v = result.get();
if(v > 9)
return v;
}
return null;
}
Of course, that example goes through the results from the beginning, not by looking at results as they complete. So here is one that accomplishes what I want, but with much more complicated code.
public Integer findFirstGt9(List<CompletableFuture<Integer>> results) {
AtomicInteger finalResult = new AtomicInteger();
CountDownLatch latch = new CountDownLatch(results.size());
for(CompletableFuture<Integer> result : results) {
result.whenComplete((v,e) -> {
if(e!=null) {
Logger.getLogger(getClass()).error("",e);
} else if(v > 9) {
finalResult.set(v);
while(latch.getCount() > 0)
latch.countDown();
return;
}
latch.countDown();
});
}
latch.await();
if(finalResult.get() > 9)
return finalResult.get();
return null;
}
Is there an api where I can just do this?
public Integer findFirstGt9(List<CompletableFuture<Integer>> results) {
Iterator<Integer> resultIt = getResultsAsAvailable(results);
for(; resultIt.hasNext();) {
Integer v = resultIt.next();
if(v > 9)
return v;
}
return null;
}
Or even better:
public Integer findFirstGt9(List<CompletableFuture<Integer>> results) {
return getFirstMatch(results, r -> {return r > 9;});
}