CompletedFuture: how to apply a function to a set of CompletingFutures?
Suppose I have 3 downloads framed as terminating futures:
CompletableFuture<Doc> dl1 = CompletableFuture.supplyAsync(() -> download("file1"));
CompletableFuture<Doc> dl2 = CompletableFuture.supplyAsync(() -> download("file2"));
CompletableFuture<Doc> dl3 = CompletableFuture.supplyAsync(() -> download("file3"));
Then they should all be handled the same way.
CompletableFuture<String> s1 = dl1.thenApply(Doc::getFilename);
CompletableFuture<String> s2 = dl2.thenApply(Doc::getFilename);
CompletableFuture<String> s3 = dl3.thenApply(Doc::getFilename);
And you can imagine several functions to be applied, all in parallel.
According to the DRY principle, this example seems out of place. So I am looking for a solution to define only 1 workflow that runs 3 times, in parallel.
How can I do that?
I tried allOf
it but it has two problems: 1) it starts blocking and 2) the return type can only handle run
, not handle it.
source to share
Stream.of("file1", "file2", "file3") // or your input in any other format, that can easily be transformed to a stream...
// .parallel() // well... depends...
.map(s -> CompletableFuture.supplyAsync(() -> download(s)))
.map(dl -> dl.thenApply(Doc::getFilename))
.map(CompletableFuture::join) // if you want to have all the results collected
.collect(Collectors.toList());
Of course, you can also combine two characters map
. But at least you don't write just x times ... If you don't like the collection List
, you can also name something else on it, for example. .forEach(System.out::println)
... .forEach
has the advantage that as soon as a response is available, the consumer is called.
Or classic: just use a loop and a list / array for input, but you might have to take care of more than you would with streams
source to share