繁体   English   中英

CompletableFuture.runAsync 吞咽异常

[英]CompletableFuture.runAsync Swallowing Exceptions

早上好,

我不太了解 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并返回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(...)断言触发。

我究竟做错了什么?

提前谢谢了!

用你的原始定义

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

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

同样,当您将相同的代码移动到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(…)返回的gameService.deregister(…).exceptionally(…)以确定它是否失败,但现在,您不是返回它而是删除引用。

要创建其完成取决于函数评估返回的未来的未来,您需要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返回的未来。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM