.exceptionally() 会捕获从嵌套期货中抛出的异常吗?或者放在哪里是正确的 .exceptionally()
Will .exceptionally() catch exceptions thrown from within nested futures? Or where is correct to put .exceptionally()
foo.thenCompose(fooResponse -> {
...
return bar.thenCompose(barResponse -> {
...
});
}).exceptionally(e -> {
...
});
这个 .exceptionally()
是否也会捕获从嵌套的 bar.thenCompose
lambda 中抛出的异常?还是我需要这样写:
foo.thenCompose(fooResponse -> {
...
return bar.thenCompose(barResponse -> {
...
}).exceptionally(nestedE -> {
...
});
}).exceptionally(e -> {
...
});
然后再抛?
是的,通过 'exceptionally' 方法你可以处理嵌套的 CompletableFuture
第一个例子将起作用
末尾的单个 exceptionally
足以用替代的普通结果值替换任何可抛出的对象,至少对于由它编辑的结果阶段 return 而言,但值得清理一下头脑导致这个问题的设置。
exceptionally
不会 捕捉到 任何异常,也没有 嵌套 期货。重要的是要理解 CompletionStage
定义的所有方法都会创建一个 new 完成阶段,其完成将受到特定方法契约的影响,但不会影响完成阶段,方法已被调用。
因此,当您使用 exceptionally
时,涉及两个未来,一个是您异常调用的未来,另一个是 return 由 exceptionally
编辑的新未来。约定是后者在正常完成的情况下以与前者相同的价值完成,但在前者异常完成的情况下具有功能评估的结果。
所以当你执行
for(int run = 0; run < 4; run++) {
CompletableFuture<String> stage1 = new CompletableFuture<>();
CompletableFuture<String> stage2 = stage1.exceptionally(t -> "alternative result");
if(run > 1) stage2.cancel(false);
if((run&1) == 0) stage1.complete("ordinary result");
else stage1.completeExceptionally(new IllegalStateException("some failure"));
stage1.whenComplete((v,t) ->
System.out.println("stage1: "+(t!=null? "failure "+t: "value "+v)));
stage2.whenComplete((v,t) ->
System.out.println("stage2: "+(t!=null? "failure "+t: "value "+v)));
System.out.println();
}
它将打印:
stage1: value ordinary result
stage2: value ordinary result
stage1: failure java.lang.IllegalStateException: some failure
stage2: value alternative result
stage1: value ordinary result
stage2: failure java.util.concurrent.CancellationException
stage1: failure java.lang.IllegalStateException: some failure
stage2: failure java.util.concurrent.CancellationException
表明无论第二阶段发生什么,第一阶段总是反映我们显式完成的结果。所以exceptionally
不捕获异常,前一阶段的异常完成永远不会改变,它所做的只是定义一个新阶段的完成。
因此,如果 stage1
是调用 stage0.thenCompose(x -> someOtherStage)
的结果,那么 stage1
和 stage2
之间的关系并不重要。重要的是 stage1
.
的完成
- 如果
stage0
异常完成,它将尝试异常完成 stage1
- 如果
stage0
以一个值完成并且函数抛出异常,它将尝试异常完成 stage1
- 如果
stage0
完成了一个值并且函数 return 已经或将异常完成的阶段 (someOtherStage
),它将尝试完成 stage1
异常地
- 如果
stage0
完成了一个值,并且函数 return 一个阶段 (someOtherStage
) 已经或将要完成一个值,它将尝试完成 stage1
具有该值
注意没有嵌套,someOtherStage
可能是新建的或已经存在的舞台,也可能在其他地方使用。由于链接总是构建不影响现有阶段的新阶段,因此这些其他地方不会受到此处发生的任何事情的影响。
进一步注意术语“尝试完成”,因为我们仍然可以在尝试之前在 stage1
上调用 complete
、completeExceptionally
或 cancel
。对于stage2
来说,以何种方式完成并不重要,重要的是结果。
因此,如果尝试从 1. 到 3. 中的任何一种情况,异常地完成 stage1
,成功,将尝试使用函数的结果完成 stage2
传递给 exceptionally
。在情况 4 中,如果尝试使用某个值完成 stage1
成功,将尝试使用该值完成 stage2
。
为了证明前一阶段历史的无关性,如果我们使用
CompletableFuture<String> stage1 = new CompletableFuture<>();
CompletableFuture<String> stage2 = stage1.thenCompose(s -> new CompletableFuture<>());
CompletableFuture<String> stage3 = stage2.exceptionally(t -> "alternative result");
stage1.complete("ordinary result"); // you can omit this line if you want
stage2.completeExceptionally(new IllegalStateException("some failure"));
stage3.whenComplete((v,t) ->
System.out.println("stage3: "+(t!=null? "failure "+t: "value "+v)));
它会打印 stage3: value alternative result
因为 stage2
已经异常完成,完成的历史完全无关紧要。 stage1.complete("ordinary result");
语句将导致对函数 return 进行评估并生成一个永远不会完成的新 CompletableFuture
,因此不会影响结果。如果我们省略这一行,stage1
将永远不会完成并且函数永远不会被评估,因此,“嵌套”阶段将永远不会被创建,但如前所述,这段历史对 stage2
.
因此,如果您最后一次调用链式完成阶段是 exceptionally(function)
,它将 return 一个新阶段,该阶段将始终使用前一阶段或 return 从 function
编辑,不管它们之前的依赖关系图看起来如何。除非 function
本身抛出异常或有人对其调用显式完成方法之一,例如 cancel
.
foo.thenCompose(fooResponse -> {
...
return bar.thenCompose(barResponse -> {
...
});
}).exceptionally(e -> {
...
});
这个 .exceptionally()
是否也会捕获从嵌套的 bar.thenCompose
lambda 中抛出的异常?还是我需要这样写:
foo.thenCompose(fooResponse -> {
...
return bar.thenCompose(barResponse -> {
...
}).exceptionally(nestedE -> {
...
});
}).exceptionally(e -> {
...
});
然后再抛?
是的,通过 'exceptionally' 方法你可以处理嵌套的 CompletableFuture 第一个例子将起作用
末尾的单个 exceptionally
足以用替代的普通结果值替换任何可抛出的对象,至少对于由它编辑的结果阶段 return 而言,但值得清理一下头脑导致这个问题的设置。
exceptionally
不会 捕捉到 任何异常,也没有 嵌套 期货。重要的是要理解 CompletionStage
定义的所有方法都会创建一个 new 完成阶段,其完成将受到特定方法契约的影响,但不会影响完成阶段,方法已被调用。
因此,当您使用 exceptionally
时,涉及两个未来,一个是您异常调用的未来,另一个是 return 由 exceptionally
编辑的新未来。约定是后者在正常完成的情况下以与前者相同的价值完成,但在前者异常完成的情况下具有功能评估的结果。
所以当你执行
for(int run = 0; run < 4; run++) {
CompletableFuture<String> stage1 = new CompletableFuture<>();
CompletableFuture<String> stage2 = stage1.exceptionally(t -> "alternative result");
if(run > 1) stage2.cancel(false);
if((run&1) == 0) stage1.complete("ordinary result");
else stage1.completeExceptionally(new IllegalStateException("some failure"));
stage1.whenComplete((v,t) ->
System.out.println("stage1: "+(t!=null? "failure "+t: "value "+v)));
stage2.whenComplete((v,t) ->
System.out.println("stage2: "+(t!=null? "failure "+t: "value "+v)));
System.out.println();
}
它将打印:
stage1: value ordinary result
stage2: value ordinary result
stage1: failure java.lang.IllegalStateException: some failure
stage2: value alternative result
stage1: value ordinary result
stage2: failure java.util.concurrent.CancellationException
stage1: failure java.lang.IllegalStateException: some failure
stage2: failure java.util.concurrent.CancellationException
表明无论第二阶段发生什么,第一阶段总是反映我们显式完成的结果。所以exceptionally
不捕获异常,前一阶段的异常完成永远不会改变,它所做的只是定义一个新阶段的完成。
因此,如果 stage1
是调用 stage0.thenCompose(x -> someOtherStage)
的结果,那么 stage1
和 stage2
之间的关系并不重要。重要的是 stage1
.
- 如果
stage0
异常完成,它将尝试异常完成stage1
- 如果
stage0
以一个值完成并且函数抛出异常,它将尝试异常完成stage1
- 如果
stage0
完成了一个值并且函数 return 已经或将异常完成的阶段 (someOtherStage
),它将尝试完成stage1
异常地 - 如果
stage0
完成了一个值,并且函数 return 一个阶段 (someOtherStage
) 已经或将要完成一个值,它将尝试完成stage1
具有该值
注意没有嵌套,someOtherStage
可能是新建的或已经存在的舞台,也可能在其他地方使用。由于链接总是构建不影响现有阶段的新阶段,因此这些其他地方不会受到此处发生的任何事情的影响。
进一步注意术语“尝试完成”,因为我们仍然可以在尝试之前在 stage1
上调用 complete
、completeExceptionally
或 cancel
。对于stage2
来说,以何种方式完成并不重要,重要的是结果。
因此,如果尝试从 1. 到 3. 中的任何一种情况,异常地完成 stage1
,成功,将尝试使用函数的结果完成 stage2
传递给 exceptionally
。在情况 4 中,如果尝试使用某个值完成 stage1
成功,将尝试使用该值完成 stage2
。
为了证明前一阶段历史的无关性,如果我们使用
CompletableFuture<String> stage1 = new CompletableFuture<>();
CompletableFuture<String> stage2 = stage1.thenCompose(s -> new CompletableFuture<>());
CompletableFuture<String> stage3 = stage2.exceptionally(t -> "alternative result");
stage1.complete("ordinary result"); // you can omit this line if you want
stage2.completeExceptionally(new IllegalStateException("some failure"));
stage3.whenComplete((v,t) ->
System.out.println("stage3: "+(t!=null? "failure "+t: "value "+v)));
它会打印 stage3: value alternative result
因为 stage2
已经异常完成,完成的历史完全无关紧要。 stage1.complete("ordinary result");
语句将导致对函数 return 进行评估并生成一个永远不会完成的新 CompletableFuture
,因此不会影响结果。如果我们省略这一行,stage1
将永远不会完成并且函数永远不会被评估,因此,“嵌套”阶段将永远不会被创建,但如前所述,这段历史对 stage2
.
因此,如果您最后一次调用链式完成阶段是 exceptionally(function)
,它将 return 一个新阶段,该阶段将始终使用前一阶段或 return 从 function
编辑,不管它们之前的依赖关系图看起来如何。除非 function
本身抛出异常或有人对其调用显式完成方法之一,例如 cancel
.