Java CompletionStage到CompletionStage <any>类型丢失

时间:2017-07-20 17:22:41

标签: java completable-future

说我有这个方法:

public CompletionStage<SomeClass> getData() {
    CompletableFuture<SomeClass> future = new CompletableFuture<>();

    return CompletableFuture.runAsync(() -> {
        // Fetch data from some source
        // Then either
        // future.complete(data);
        // or fail
        // future.completeExceptionally(e);
    });

    return future;
}

现在我想要一个方法,调用getData,进行操作,然后返回CompletionStage<Either<ErrorResponse, Data>>

public CompletionStage<Either<ErrorResponse, Data>> modifyData() {
    return getData()
       .thenCompose(d -> CompletableFuture.completedFuture(Either.right(d)))
       .exceptionally(e -> Either.left(ErrorResponse.create(e)));
}

当我这样做时,exceptionally内的类型丢失,编译器认为我正在返回类型Either<Object, Data>

但是,如果我将该代码更改为:

public CompletionStage<Either<ErrorResponse, Data>> modifyData() {
    CompletableFuture<Either<ErrorResponse, Data>> future = new CompetableFuture<>();

    CompletableFuture.runAsync(() -> {
        getData()
           .thenCompose(d -> future.complete(Either.right(d)));
           .exceptionally(e -> 
               future.complete(Either.left(ErrorResponse.create(e)))
    });

    return future;
}

然后它工作正常。为什么类型会丢失?

1 个答案:

答案 0 :(得分:1)

你有

public CompletionStage<Either<ErrorResponse, Data>> modifyData() {
    return getData()
       .thenCompose(d -> CompletableFuture.completedFuture(Either.right(d)))
       .exceptionally(e -> Either.left(ErrorResponse.create(e)));
}

thenCompose是一种通用方法,但是您没有为Java提供足够的类型信息来推断您希望其类型参数U绑定到Either<ErrorResponse, Data>。对exceptionally的调用(即使它是通用的)也无法将类型信息反馈给thenCompose的调用。

目前,它会为Object的第一个类型参数推断Either。因此thenCompose会返回CompletionStage<Either<Object, Data>>。传播到exceptionally。由于CompletionStage<Either<Object, Data>>不是CompletionStage<Either<ErrorResponse, Data>>,因此返回值的类型无效。

您可以通过提供显式类型参数来添加必要的类型信息。

public CompletionStage<Either<ErrorResponse, Data>> modifyData() {
    return getData()
       .<Either<ErrorResponse, Data>>thenCompose(d -> CompletableFuture.completedFuture(Either.right(d)))
       .exceptionally(e -> Either.left(ErrorResponse.create(e)));
}

或更接近有问题的调用

public CompletionStage<Either<ErrorResponse, Data>> modifyData() {
    return getData()
       .thenCompose(d -> CompletableFuture.completedFuture(Either.<ErrorResponse, Data>right(d)))
       .exceptionally(e -> Either.left(ErrorResponse.create(e)));
}

现在Java不必尝试猜测。它知道你的意思。

或者,我会使用CompletableFuture#handle来处理异常情况。

return getData()
            .handle((d, e) -> {
                if (e == null) {
                    return Either.right(d);
                }
                return Either.left(ErrorResponse.create(e));
            });
}

类型信息是自包含的。其余的主要是意见问题。