组合多个CompletableFutures

时间:2016-06-26 09:18:35

标签: java-8 completable-future

我有以下组件:

private JobInfo aggregateJobInfo() {
    final JobsResult jobsResult = restClient().getJobs();
    final List<String> jobIds = extractJobIds(jobsResult);

    //fetch details, exceptions and config for each job
    final List<JobDetails> jobDetails = jobIds.stream().map(jobId -> {
        final JobDetailResult jobDetailResult = restClient().getJobDetails(jobId);
        final JobExceptionsResult jobExceptionsResult = restClient().getJobExceptions(jobId);
        final JobConfigResult jobConfigResult = restClient().getJobConfig(jobId);
        return new JobDetails(jobDetailResult, jobExceptionsResult, jobConfigResult);
    }).collect(Collectors.toList());
    return new JobInfo(jobsResult, jobDetails);
}

private static List<String> extractJobIds(final JobsResult jobsResult) {
    final ArrayList<String> jobIds = new ArrayList<>();
    jobIds.addAll(jobsResult.getRunning());
    jobIds.addAll(jobsResult.getFinished());
    jobIds.addAll(jobsResult.getCanceled());
    jobIds.addAll(jobsResult.getFailed());
    return jobIds;
}

它只是调用一些ENDPOINTS并混合一些数据。现在我试图通过使用CompletableFutures来实现非阻塞,我以前没有真正使用它。

private CompletableFuture<JobInfo> aggregateJobInfo() {
    final CompletableFuture<JobsResult> jobsResultFuture = restClient().getJobs();
    final CompletableFuture<List<String>> jobIdsFuture = jobsResultFuture.thenApply(JobInfoCollector::extractJobIds);

     //fetch details, exceptions and config for each job
    final CompletableFuture<List<CompletableFuture<JobDetails>>> jobDetailsFuture = jobIdsFuture.thenApply(jobIds -> {
        return jobIds.stream().map(jobId -> {
            final CompletableFuture<JobDetailResult> jobDetailsResultFuture = restClient().getJobDetails(jobId);
            final CompletableFuture<JobExceptionsResult> jobExceptionsFuture = restClient().getJobExceptions(jobId);
            final CompletableFuture<JobConfigResult> jobConfigFuture = restClient().getJobConfig(jobId);
            return jobDetailsResultFuture.thenCompose(jobDetailResult -> {
                return jobExceptionsFuture.thenCombine(jobConfigFuture, (jobExceptionsResult, jobConfigResult) -> {
                    return new JobDetails(jobDetailResult, jobExceptionsResult, jobConfigResult);
                });
            });

        }).collect(Collectors.toList());
    });
    return null;

我的问题是当JobInfo是`new JobInfo(jobsResult,jobDetails)时,如何在这里创建CompletableFuture?!

正如我所说,我是新手,也许我的方法很糟糕,有更好的解决方案?

感谢任何想法,谢谢

第一个工作版本:

private CompletableFuture<JobInfo> aggregateJobInfo() {

    final CompletableFuture<JobsResult> jobsResultFuture = restClient().getJobs();
    final CompletableFuture<List<String>> jobIdsFuture = jobsResultFuture.thenApply(JobInfoCollector::extractJobIds);

    final CompletableFuture<List<CompletableFuture<JobDetails>>> jobDetailsFutureListFuture =
            jobIdsFuture.thenApply(jobIds -> jobIds.stream().map(jobId -> {
                final CompletableFuture<JobDetailResult> jobDetailsResultFuture = restClient().getJobDetails(jobId);
                final CompletableFuture<JobExceptionsResult> jobExceptionsFuture = restClient().getJobExceptions(jobId);
                final CompletableFuture<JobConfigResult> jobConfigFuture = restClient().getJobConfig(jobId);
                return jobDetailsResultFuture.thenCompose(jobDetailResult ->
                        jobExceptionsFuture.thenCombine(jobConfigFuture, (jobExceptionsResult, jobConfigResult) ->
                                new JobDetails(jobDetailResult, jobExceptionsResult, jobConfigResult)));
            }).collect(Collectors.toList()));

    return jobDetailsFutureListFuture.thenCompose(jobDetailsFutures ->
            CompletableFuture.allOf(jobDetailsFutures.toArray(
                    new CompletableFuture[jobDetailsFutures.size()])).thenApply(aVoid ->
                    jobDetailsFutures.stream()
                            .map(CompletableFuture::join)
                            .collect(Collectors.toList())))
            .thenApply(jobDetails -> jobsResultFuture.thenApply(jobsResult ->
                    new JobInfo(jobsResult, jobDetails)))
            .join();
}

1 个答案:

答案 0 :(得分:4)

你有:

  • CompletableFuture<JobsResult> jobsResultFuture
  • CompletableFuture<List<CompletableFuture<JobDetails>>> jobDetailsFuture
  • JobInfo(JobsResult a, List<JobDetails> b)

你想要

CompletableFuture<JobInfo>

其他观察:jobDetailsFuture只能在jobsResultFuture完成后完成。

所以你可以实现以下内容:

  1. List<CompletableFuture<JobDetails>> - &gt; Void通过allOf
  2. 中的thenCompose Void
  3. List<CompletableFuture<JobDetails>> + List<JobDetails>(作为已捕获的var) - &gt; thenApply通过List<JobDetails>
  4. CompletableFuture<JobsResult> + JobInfo(作为已捕获的var) - &gt; thenApply通过get()
  5. 您可以通过thenCombine在这些映射器函数中简单地展开期货,因为期货保证在那时由于其祖先期货的依赖性而在那时完成。

    使用{{1}}和流减少的其他方法是可能的,但更冗长并创造更多的中间期货。