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

问题描述

Java 8环境.

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

run tasks using CompletableFuture.allOf() concurrently andthen 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中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-22 20:40
查看更多