如何从CompletableFuture< List< CustomObject>>中获取结果在Java 8中 [英] How to get result from CompletableFuture<List<CustomObject>> in Java 8

查看:71
本文介绍了如何从CompletableFuture< List< CustomObject>>中获取结果在Java 8中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java 8环境.

同时使用CompletableFuture.allOf()运行任务,并 然后从每个线程获取每个结果,然后将所有结果合并到一个CombinedResult中并返回.

run tasks using CompletableFuture.allOf() concurrently and then get each result from each thread and then combine all results into one combinedResult and return it.

在下面的代码中,获取结果(= List<Student>)不必是I.和II之间的代码. 他们说我需要使用join()但没有用

In the below code, to get the result ( = List<Student> ) it doesn't have to be the code between I. and II. They say I need to use join() but didn't work

我也从

带有Collection或Java 8的Java 8 CompletableFuture.allOf(...)列表
和其他链接,但对我没有任何帮助. 我想我错过了一些非常简单的部分.有人知道如何使它工作吗?

Java 8 CompletableFuture.allOf(...) with Collection or List
and other links, but nothing works for me. I think I miss some very easy part. Does someone know how to make it work?

public class Test1 {
    public static void main(String[] args) {
        Test1 t = new Test1();
        Map<Major, List<Student>> allMajorStudentListMap = new HashMap<>();
        // fill out some data toallMajorStudentListMap
        t.getData(allMajorStudentListMap);
    }

    List<Student> getData(Map<Major, List<Student>> allMajorStudentListMap) {
        List<CompletableFuture<List<Student>>> completableFutures = new ArrayList<>();

        // suppose the size of completableFutures is 10
        for(Map.Entry<Major, List<Student>> entry: allMajorStudentListMap.entrySet()) {
            CompletableFuture<List<Student>> future = CompletableFuture.supplyAsync(() -> getDetailedStudents(entry));
            completableFutures.add(future);
        }

        // want to run 10 jobs concurrently --> get the 10 result and then combine these 10 results into one
        // finally want to sent the combined 10 results at one in this method

        // I. ======================= I got this code from somewhere     ==========================

        CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]))
                .exceptionally(ex -> null)
                .join();

        Map<Boolean, List<CompletableFuture<List<Student>>>> result =
                completableFutures.stream()
                        .collect(Collectors.partitioningBy(CompletableFuture::isCompletedExceptionally));

        result.forEach((k, clist) -> {
            System.out.printf("k = " + k);

            for(CompletableFuture<List<Student>> student: clist) {

            // 3) don't know how to get only List<Student> and then print here
            // tried this and that but didn't work
            // student.get() has compile error

            }

        });

        // II. =============================================================================================


        // want to return combined List<Student>
        return ???;
    }

    List<Student> getDetailedStudents(Map.Entry<Major, List<Student>> entry) 
    {
        List<Student> studentList = new ArrayList<>();

        Major major = entry.getKey();
        String majorCode = major.getMajorCode();
        String majorName = major.getMajorName();
        List<Student> studentListList = entry.getValue();           

        studentList.addAll(getDataFromRemote(majorCode, majorName, studentList)));
        return studentList;
    }

    List<Student> getDataFromRemote(String majorCode, String majorName, List<studentList> studentList) {
        // do something and then return list of Student

        return detailedStudentList;
    }
}

推荐答案

在这里,我创建了一个稍作改动的(直接使用List<Student>代替Map<K,V>)版本的工作示例.您可以将您的解决方案与此解决方案进行比较.

Here I have created a slightly altered (directly used List<Student> instead of Map<K,V>) version of working sample. You can compare your solution with this one.

总共查询五次学生名单,并且每次并发执行一次,这在人为延迟3秒后返回了其中有一个学生对象的完整学生名单.因此,从理论上讲,如果每个对象同时运行,则在延迟3秒后,应该显示所有5个学生对象.

Totally five times the students list is queried and each gets executed concurrently which returns a completable list of students with ONE student object in it after an artificial delay of 3 seconds. So in theory if each runs concurrently, after 3 seconds of delay all of the 5 student object should get displayed.

如果您注意到主方法的开始和结束之间的时间间隔,则大约为3秒.

if you notice the time gap between start and end of the main method, it will be around 3 seconds.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.*;
import java.util.stream.Collectors;

public class CompletableFutureTest {
    private static int counter = 0;
    public static void main(String[] args) {
        System.out.println("Program started at " + new Date());
       List<Student> allStudents = new ArrayList<>();
        new CompletableFutureTest().getData(allStudents);
        for(Student st : allStudents){
            System.out.println(st.getName());
        }
        System.out.println("Program ended at " + new Date());
    }

    private void getData(List<Student> resultToFillIn){
        List<CompletableFuture<List<Student>>> completableFutures = new ArrayList<>();
        //for simulation purpose just running regular for loop 5 times instead of yours          
        final Integer integer = new Integer(0);
        for(int i=0; i < 5; i++){
            completableFutures.add(CompletableFuture.supplyAsync(() -> getStudentsBatch()));
        }
        CompletableFuture<List<Student>>[] cfArray = new CompletableFuture[completableFutures.size()];
        cfArray = completableFutures.toArray(cfArray);
        CompletableFuture.allOf(cfArray)
                .exceptionally(ex ->
                {
                    ex.printStackTrace();
                    return null;
                }).join();
       List<CompletableFuture<List<Student>>> completedFutures = completableFutures.stream().filter(cf -> !cf.isCompletedExceptionally()).collect(Collectors.toList());
       for(CompletableFuture<List<Student>> cf : completedFutures){
           resultToFillIn.addAll(cf.join());
       }
    }

    private List<Student> getStudentsBatch() {
        //adding some delay
        try {
            Thread.sleep( 3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        List<Student> students = new ArrayList<>();
        Student student = new Student();
        student.setName("Student " + ++counter);
        students.add(student);
        return students;
    }

    public static class Student{
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public static class Major{
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

由于此操作如上所述,所以CompletableFuture.allOf(...)正常工作.

Since this works as explained above, CompletableFuture.allOf(...) is working.

但是,请尽量避免使用j oin(),因为它会暂停当前正在执行的线程.如果选择真正的异步编程,则可以使用thenAccept(x -> {})thenApply(x -> {})回调方法来代替join().

But, try avoid using join() whenever you can, as it will stall the currently executing thread. If you opt for truly asynchronous programming, then instead of join() you can use thenAccept(x -> {}), thenApply(x -> {}) callback methods.

希望这对您有所帮助.

Hope this helps you.

这篇关于如何从CompletableFuture&lt; List&lt; CustomObject&gt;&gt;中获取结果在Java 8中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆