【发布时间】:2018-11-01 00:11:08
【问题描述】:
我想过滤掉第一个CompletableFuture 之后的重复项,然后使用另一个CompletableFuture 调用第二个阶段。我尝试了什么:
@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());
如您所见,distinctByKey 将调用 get,这将直接使并发变为顺序性。
我应该怎么做才能使它再次CONCURRENT但同时保留distinct功能?
或
我只有一个选择?
要等待整个第一阶段完成,然后开始第二阶段?
【问题讨论】:
-
小心,
thenApply和thenCompose是同步的。您可能更喜欢thenApplyAsync和thenComposeAsync。 -
@kagmole 感谢您的回复。但我确实不认为你明白这一点。我对 *Async 非常了解,因为它们有据可查。我希望 second 在 first 和 thenCompose 之后运行就足够了,因为它将与 first 在同一个线程中工作 阶段。
-
我明白了,确实还有
distinctByKey的问题。我可能有一个基于Optional的建议,但我担心它最终会变得不必要地臃肿。 -
@kagmole 感谢您的idea,我会试一试。 B.T.W 实际上从一开始就是 distinct 问题。哈哈,谢谢你,伙计。
-
是的,抱歉我不是很清楚。 :)
标签: java java-stream distinct completable-future