I wanna to filter out the duplicates after the first CompletableFuture
and then invoke the second stage using another CompletableFuture
. What I tried:
@FunctionalInterface
public interface FunctionWithExceptions<T, R, E extends Exception> {
R process(T t) throws E;
}
public static <T> Predicate<T> distinctByKey(FunctionWithExceptions<? super T, ?, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> {
String key = "";
try {
key = (String) keyExtractor.process(t);
} catch (Exception e) {
log.info("Get instanceIp failed!");
}
return seen.add(key);
};
}
List<CompletableFuture<InstanceDo>> instanceFutures = podNames.stream()
.map(podName -> CompletableFuture.supplyAsync(RethrowExceptionUtil.rethrowSupplier(() -> {
PodDo podDo = getPodRetriever().getPod(envId, podName);
podDoList.add(podDo);
return podDo;
}), executor))
.map(future -> future.thenApply(podDo -> podDo.getInstanceName()))
.filter(distinctByKey(CompletableFuture::get))
.map(future -> future.thenCompose(instanceName ->
CompletableFuture.supplyAsync(() -> get(envId, instanceName), executor)))
.collect(Collectors.toList());
As you can see, the distinctByKey
will invoke get
which will directly make the concurrency to sequentiality.
What should I do to make it CONCURRENT again but meantime retain the distinct feature?
OR
I only have one choice?
To wait the whole first stage to complete and then start the second stage?