gpt4 book ai didi

java - CompletableFuture.runAsync 吞没异常

转载 作者:行者123 更新时间:2023-12-02 09:05:18 26 4
gpt4 key购买 nike

早上好,

我还没有完全掌握 CompletableFutures 的窍门(我是一位经验丰富的开发人员,但我并不觉得它们特别直观!)。

给出以下代码片段:

public CompletionStage<Void> leaveGame(GameService gameService)
{
return gameService.deregister(playerName)
.exceptionally(t -> {
LOGGER.info("Could not deregister: {}", t.getMessage());
throw new CompletionException(t);
});
}

由单元测试调用:

@Test
public void shouldCompleteExceptionallyForFailedLeave()
{
var failFlow = new CompletableFuture<Void>();
failFlow.completeExceptionally(new Exception("TestNonExistentPlayer"));
when(mockedGameService.deregister(any(String.class))).thenReturn(failFlow);

try
{
player.leaveGame(mockedGameService).toCompletableFuture().get();
fail("Exception should have been thrown");
}
catch (Exception e)
{
assertEquals(Exception.class, e.getCause().getClass());
}
verify(mockedGameService, times(1)).deregister(any(String.class));
}

它模拟 gameService.deregister(...) 以完成异常并返回 Exception

在上述情况下,正如预期的那样,异常分支被触发,消息被记录,并且单元测试中的异常被捕获,即 fail(...) 断言不是触发。

但是,当我想在离开游戏之前运行 CompletionStage 时,例如:

public CompletionStage<Void> leaveGame(GameService gameService)
{
return CompletableFuture.runAsync(() -> System.out.println("BLAH"))
.thenRun(() -> gameService.deregister(playerName)
.exceptionally(t -> {
LOGGER.info("Could not deregister: {}", t.getMessage());
throw new CompletionException(t);
}));
}

异常分支仍然仍然被触发,但是异常现在没有被测试方法捕获,即fail(...)断言is 触发。

我做错了什么?

非常感谢!

最佳答案

用你原来的定义

public CompletionStage<Void> leaveGame(GameService gameService)
{
return gameService.deregister(playerName)
.exceptionally(t -> {
LOGGER.info("Could not deregister: {}", t.getMessage());
throw new CompletionException(t);
});
}

方法leaveGame没有抛出异常,但总是返回一个 future。调用者必须检查 future 来确定封装的操作是否失败。

同样,当您将相同的代码移至 Runnable 时喜欢

public CompletionStage<Void> leaveGame(GameService gameService)
{
return CompletableFuture.runAsync(() -> System.out.println("BLAH"))
.thenRun(() -> gameService.deregister(playerName)
.exceptionally(t -> {
LOGGER.info("Could not deregister: {}", t.getMessage());
throw new CompletionException(t);
}));
}

Runnable不会抛出异常。仍然需要检查 gameService.deregister(…).exceptionally(…) 返回的 future找出它是否失败,但现在,您不会返回它,而只是删除引用。

要创建一个其完成取决于函数求值返回的 future 的 future,您需要 thenCompose :

public CompletionStage<Void> leaveGame(GameService gameService)
{
return CompletableFuture.runAsync(() -> System.out.println("BLAH"))
.thenCompose(voidArg -> gameService.deregister(playerName)
.exceptionally(t -> {
LOGGER.info("Could not deregister: {}", t.getMessage());
throw new CompletionException(t);
}));
}

所以现在您正在实现 Function<Void,CompletionStage<Void>>而不是Runnable函数返回的阶段将用于完成leaveGame返回的 future 。 .

关于java - CompletableFuture.runAsync 吞没异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59857112/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com