Currently to do something simple with Collections of CompletionStage requires jumping through several ugly hoops:
public static CompletionStage<String> translate(String foo) {
// just example code to reproduce
return CompletableFuture.completedFuture("translated " + foo);
}
public static CompletionStage<List<String>> translateAllAsync(List<String> input) {
List<CompletableFuture<String>> tFutures = input.stream()
.map(s -> translate(s)
.toCompletableFuture())
.collect(Collectors.toList()); // cannot use toArray because of generics Arrays creation :-(
return CompletableFuture.allOf(tFutures.toArray(new CompletableFuture<?>[0])) // not using size() on purpose, see comments
.thenApply(nil -> tFutures.stream()
.map(f -> f.join())
.map(s -> s.toUpperCase())
.collect(Collectors.toList()));
}
What I want to write is:
public CompletionStage<List<String>> translateAllAsync(List<String> input) {
// allOf takes a collection< futures<X>>,
// and returns a future<collection<x>> for thenApply()
return XXXUtil.allOf(input.stream()
.map(s -> translate(s))
.collect(Collectors.toList()))
.thenApply(translations -> translations.stream()
.map(s -> s.toUpperCase())
.collect(Collectors.toList()));
}
The whole ceremony about toCompletableFuture and converting to an Array and join is boilerplate distracting from the actual code semantics.
Possibly having a version of allOf() returning a Future<Collection<Future<X>>>
instead of Future<Collection<X>>
may also be useful in some cases.
I could try implementing XXXUtil myself, but I wonder if there already is a mature 3rdparty library for this and similar issues (Such as Spotify's CompletableFutures). If so, I'd like to see the equivalent code for such a library as an answer.
Or maybe the original code posted above can somehow be written more compactly in a different way?
JUnit test code:
@Test
public void testTranslate() throws Exception {
List<String> list = translateAllAsync(Arrays.asList("foo", "bar")).toCompletableFuture().get();
Collections.sort(list);
assertEquals(list,
Arrays.asList("TRANSLATED BAR", "TRANSLATED FOO"));
}