Java 8 Completable Futures allOf different data types

后端 未结 4 1629
你的背包
你的背包 2020-12-14 09:52

I have 3 CompletableFutures all 3 returning different data types.

I am looking to create a result object that is a composition of the result returned by all the 3 fu

4条回答
  •  执笔经年
    2020-12-14 10:31

    Your attempt is going into the right direction, but not correct. Your method getResultClassD() returns an already instantiated object of type ClassD on which an arbitrary thread will call modifying methods, without the caller of getResultClassD() noticing. This can cause race conditions, if the modifying methods are not thread safe on their own, further, the caller will never know, when the ClassD instance is actually ready for use.

    A correct solution would be:

    public CompletableFuture getResultClassD() {
    
        CompletableFuture classAFuture
            = CompletableFuture.supplyAsync(() -> service.getClassA() );
        CompletableFuture classBFuture
            = CompletableFuture.supplyAsync(() -> service.getClassB() );
        CompletableFuture classCFuture
            = CompletableFuture.supplyAsync(() -> service.getClassC() );
    
        return CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
             .thenApplyAsync(dummy -> {
                ClassD resultClass = new ClassD();
    
                ClassA classA = classAFuture.join();
                if (classA != null) {
                    resultClass.setClassA(classA);
                }
    
                ClassB classB = classBFuture.join();
                if (classB != null) {
                    resultClass.setClassB(classB);
                }
    
                ClassC classC = classCFuture.join();
                if (classC != null) {
                    resultClass.setClassC(classC);
                }
    
                return resultClass;
             });
    }
    

    Now, the caller of getResultClassD() can use the returned CompletableFuture to query the progress state or chain dependent actions or use join() to retrieve the result, once the operation is completed.

    To address the other questions, yes, this operation is asynchronous and the use of join() within the lambda expressions is appropriate. join was exactly created because Future.get(), which is declared to throw checked exceptions, makes the use within these lambda expressions unnecessarily hard.

    Note that the null tests are only useful, if these service.getClassX() can actually return null. If one of the service calls fails with an exception, the entire operation (represented by CompletableFuture) will complete exceptionally.

提交回复
热议问题