Adam
Adam

Reputation: 6733

How to call parameterless function after CompletableFuture.allOf

I have an async function in java. I want to make async calls to a number of APIs (in parallel) then create a response. Since I need the different results, I though to save them in the class. I have helper functions to make the calls to the external APIs (classes with a call function which return CompletableFuture<List<T>>). I can do this like this:

public class MyAction{
   private List<Bar> bars;
   private List<Baz> bazs;

   public CompletableFuture<Foo> run() {
       CompletableFuture<Void> fetchBars = new BarFetcher().call().thenAccept(this::populateBars);
       CompletableFuture<Void> fetchBazs = new BazFetcher().call().thenAccept(this::populateBazs);

       return CompletableFuture.allOf(fetchBars, fetchBazs).thenApply(this::getFoo);
   }

   private void populateBars(final List<Bar> bars) {
       this.bars = bars;
   }

   private void populateBaz(final List<Baz> bazs) {
       this.bazs = bazs;
   }

   private Foo getFoo(final Void dummy) {
       return new Foo(bars, bazs);
   }
}

But I had to add an unnecessary parameter (final Void dummy) to the getFoo function to make it work. Can I avoid this? if should really just be getFoo() not getFoo(final Void dummy). Is there any way to wait for multiple futures to complete and then chain in another function without passing it directly any data?

Note: The example only has two initial calls to fetch data (fetchbars and fetchBazs) before the final processing (getFoo). However, I actually will have more than two. I currently have three, but it may grow by one or two more. I would like to run all the initial calls in parallel, then the final processing once all have completed.

Upvotes: 2

Views: 1112

Answers (2)

Holger
Holger

Reputation: 298233

Use the right tool for the job. To combine two futures, just use

public CompletableFuture<Foo> run() {
    return new BarFetcher().call().thenCombine(new BazFetcher().call(),
        (List<Bar> bars, List<Baz> bazs) -> new Foo(bars, bazs));
}

or even simpler

public CompletableFuture<Foo> run() {
    return new BarFetcher().call().thenCombine(new BazFetcher().call(), Foo::new);
}

Upvotes: 3

Ousmane D.
Ousmane D.

Reputation: 56433

you could change the use of method reference to a lambda as follows:

return CompletableFuture.allOf(fetchBars, fetchBazs)
                        .thenApply(e -> getFoo());

then you don't have to introduce a dummy parameter.


Note, I am not that familiar with the CompletableFuture API so, there may be more suitable solutions out there.

Upvotes: 0

Related Questions