I am trying to understand CompletableFuture
API, and I got stuck at the following problem.
allOf
by itself only returns a CompletableFuture<void>
, so it only makes sense to have a slightly better interface with a function called allResultsOf
: Such function should be generic, and receive as argument objects of type List<CompletableFuture<T>>
and return an object of type CompletableFuture<List<T>>
My attempt at this function declaration was:
public static CompletableFuture<List<T>> allResultsOf(List<CompletableFuture<T>> completableFutures) {
CompletableFuture<Void> allFutures = CompletableFuture
.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()]));
CompletableFuture<List<T>> allCompletableFuture = allFutures.thenApply(
future -> {
return completableFutures.stream()
.map(completableFuture -> completableFuture.join())
.collect(Collectors.toList());
});
return allCompletableFuture;
}
However, in my (attached) example snippet, this function gives this compilation error:
error: incompatible types: List<CompletableFuture<Test.GreetHolder>> cannot be converted to List<CompletableFuture<?>> CompletableFuture<List> allCompletableFuture = allResultsOf(completableFutures);
I'm not sure what the problem is here
Example code (extracted from here):
import java.util.*;
import java.util.stream.*;
import java.lang.*;
import java.io.*;
import java.util.concurrent.*;
// The main method must be in a class named "Main".
class Main {
static class Test {
private ExecutorService executor;
public Test(ExecutorService es) {
executor = es;
}
public class GreetHolder {
private String greet;
public GreetHolder(String greet) {
this.greet = greet;
}
public String getGreet() {
return greet;
}
public void setGreet(String greet) {
this.greet = greet;
}
public String toString() {
return getGreet();
}
}
private CompletableFuture<GreetHolder> getGreeting(String lang) {
return CompletableFuture.supplyAsync( () -> {
try {
System.out.println("Task execution started for lang =" + lang);
Thread.sleep(200);
System.out.println("Task execution stopped for lang =" + lang);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new GreetHolder(getGreet(lang));
}, executor);
}
public String getGreet(String lang) {
if (lang.equals("EN")) {
return "Hello";
} else if (lang.equals("ES")) {
return "Hola";
} else if (lang.equals("SN")) {
return "Ayubovan";
} else {
throw new IllegalArgumentException("Invalid lang param");
}
}
public CompletableFuture<List<Test.GreetHolder>> run() {
List<String> langList = Arrays.asList("EN", "ES", "SN"); //, "EX");
List<CompletableFuture<Test.GreetHolder>> completableFutures =
langList.stream().map(lang -> getGreeting(lang))
//.map(CompletableFuture::join);
.collect(Collectors.toList());
// return completableFutures;
CompletableFuture<Void> allFutures = CompletableFuture
.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()]));
CompletableFuture<List<GreetHolder>> allCompletableFuture = allFutures.thenApply(
future -> {
System.out.println(String.format("%s <- future", future));
return completableFutures.stream()
.map(completableFuture -> completableFuture.join())
.collect(Collectors.toList());
});
System.out.println(String.format("%s <- allCompletableFuture", allCompletableFuture));
//return allCompletableFuture;
CompletableFuture completableFuture = allCompletableFuture.thenApply(
greets -> {
return greets
.stream()
.map(GreetHolder::getGreet)
.collect(Collectors.toList());
});
return completableFuture;
}
public static CompletableFuture<List<T>> allResultsOf(List<CompletableFuture<T>> completableFutures) {
CompletableFuture<Void> allFutures = CompletableFuture
.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()]));
CompletableFuture<List<T>> allCompletableFuture = allFutures.thenApply(
future -> {
System.out.println(String.format("%s <- future", future));
return completableFutures.stream()
.map(completableFuture -> completableFuture.join())
.collect(Collectors.toList());
});
return allCompletableFuture;
}
public CompletableFuture<List<Test.GreetHolder>> run_tidier() {
List<String> langList = Arrays.asList("EN", "ES", "SN"); //, "EX");
List<CompletableFuture<Test.GreetHolder>> completableFutures =
langList.stream().map(lang -> getGreeting(lang))
//.map(CompletableFuture::join);
.collect(Collectors.toList());
CompletableFuture<List<GreetHolder>> allCompletableFuture = allResultsOf(completableFutures);
System.out.println(String.format("%s <- allCompletableFuture", allCompletableFuture));
CompletableFuture completableFuture = allCompletableFuture.thenApply(
greets -> {
return greets
.stream()
.map(GreetHolder::getGreet)
.collect(Collectors.toList());
});
return completableFuture;
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService pool = Executors.newFixedThreadPool(2);
Test t = new Test(pool);
System.out.println(String.format("%s world!", t.getGreet("EN")));
CompletableFuture cf = t.run();
System.out.println(String.format("%s <- cf", cf.get()));
}
}