为CompletableFuture创建一个通用数组

9

我需要创建一个泛型的 CompletableFuture 对象数组,这样我才能将其传递给 CompletableFuture.allOf 方法来获取一个 CompletableFuture 以同步线程。但是由于它是一个泛型,我无法创建它。一个显而易见的解决方案是创建一个列表,然后在其上调用 toArray,但这将不够高效。是否有更好的方法?下面是我的代码:

// Current solution: 
List<CompletableFuture<List<ReportComparable>>> newReports = new ArrayList<>();

// Loop and add CompletableFuture objects to this list

// Collect all the retrieved objects here(Sync Threads).
    try {
        List<List<ReportComparable>> newReps = CompletableFuture.allOf((CompletableFuture<?>[]) newReports.toArray()).get();
    } catch (InterruptedException | ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
1个回答

6
你的问题中存在几个错误的假设。
  • You can’t do (CompletableFuture<?>[]) newReports.toArray(). The parameterless toArray() method will return Object[] and the casting attempt will cause a ClassCastException. Only the toArray(T[]) method accepting an existing array will return an array of the same type, which brings you back to square zero

  • CompletableFuture.allOf returns a CompletableFuture<Void>, so you can’t call get() on it and expect to get a List<List<ReportComparable>>. You have to assemble the result list yourself after completion.

  • There is no problem creating an array of a generic class, when all type arguments are wildcards. So

    CompletableFuture<?>[] array = new CompletableFuture<?>[100];
    

    works.

  • When you have an arbitrary number of elements, adding them to a List and invoking toArray on it, isn’t necessarily inefficient. The alternative, dealing with an array and an index manually, is doing the same as an ArrayList, but error prone. The single copying step of toArray is rarely performance relevant.

    Also keep in mind, since the CompletableFuture.allOf returns CompletableFuture<Void> you might need the List<CompletableFuture<List<ReportComparable>>> anyway to be able to construct the desired List<List<ReportComparable>> after the completion.

    On the other hand, when you have a fixed number of arguments, you may call the varargs method CompletableFuture.allOf directly without manual array creation.


但是,当您希望通过调用 get()立即使用allOf返回的CompletableFuture时,“等待所有”操作没有任何好处。

在完成后,通过查询单个CompletableFuture实例并将结果添加到结果List中,您会隐式地获得相同的效果,因为CompletableFuture.allOf不会为您执行此操作。


allOf 会并行执行,而在循环中调用 get() 则是顺序执行的,对吗?另外,如果我从该 CompletableFuture 中移除 get 调用,并循环遍历列表并调用 get() 并将返回的项添加到我的列表中,那么比直接在每个对象上调用 get 更快吗? - ayushgp
1
调用allOf不会影响各个future的完成方式。这已在创建它们时设置好了。无论哪种情况,您都在等待所有future完成,因此需要完全相同的时间。 - Holger
好的,我认为循环调用get方法比将它们包装在一个future中并调用其get方法更糟糕。谢谢!另外,我还有一个关于CompletableFuture的问题,如果您能回答:https://dev59.com/dlcP5IYBdhLWcg3wcZck#44410084 - ayushgp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接