Usually with CompletableFuture I would call thenApply or some other method to do something as soon as the result is available. However, I now have a situation where I want to process the results until I get a positive result, and then ignore all further results.
If I just wanted to get the first available result, I could use CompletableFuture.anyOf (although I don't like converting the list to an array just for calling anyOf). But that is not what I want. I want to get the first result, and if it does not have the desired result, I want to process the second available result and so on until I get the desired result.
Here is a simple example that goes through all the results and returns the first value it finds that is greater than 9. (Note that this is not my real task. This is 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, this example goes through the results from the very beginning, and not by searching for the results as they are completed. So here is what accomplishes what I want, but with much more complex 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 any api where I can 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;}); }