在异步执行时停止函数链执行的最佳实践是什么?

我这里有这个功能:


Function<Integer, Integer> func = (value) -> value + 5;

        func = func.andThen((value) -> {

            //Imagine that here some code executed and raised an exception, I'm throwing it 

            //manually just for the sake of this example.

            throw new RuntimeException("failed");

        });

        func = func.andThen((value) -> {

            System.out.println("Reached last function !");

            return value;

        });

        executeFunction(func);

现在,您可以看到我在第一个 andThen 方法中引发了运行时异常。那是因为我想阻止第二个 andThen 被执行。这是最好的方法吗?


另外,我注意到,如果我在不同的线程(异步)中执行此函数,则异常不会打印在我的控制台中,并且我想知道异常发生了。


private static void executeFunction(Function<Integer, Integer> function) {

        CompletableFuture.supplyAsync(() -> function.apply(100));

    }

在这种情况下,如果我想确保记录异常,但 andThen 链中的下一个函数没有执行,我应该记录并抛出异常吗?这不是一个ati模式吗?


三国纷争
浏览 163回答 3
3回答

慕尼黑8549860

实例化和抛出大量异常可能会变得相当昂贵,这就是为什么它们应该仅限于特殊情况。相反,您可以使用Optional来控制流:func = (value) -> Optional.of(value + 5);func = func.andThen((optionalValue) -> {    // Instead of throwing an exception, return an empty Optional    System.out.println("Log the failure");    return Optional.empty();});func = func.andThen((optionalValue) -> {    optionalValue.map((value) -> { // This lambda will only execute if optionalValue is not empty        System.out.println("Reached last function !");        return value; // map wraps this in an Optional    });});// Finally, unwrap the value. Optional provides a number of ways to do this, depending on how you want to handle failure/emptyfunc = func.andThen((optional) -> optional.orElse(...));executeFunction(func);

冉冉说

您可以为函数/可运行对象编写一个包装器,在任务失败时记录并退出。就像这样:class Runnables{&nbsp; &nbsp; public static Runnable trying(Runnable... runnables)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return () ->&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int successes = 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(Runnable runnable : runnables)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; runnable.run();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; successes++;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch(Throwable t)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logger.error("Exception thrown from "+successes+"th runnable: ",t);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }}然后:private static void executeFunction(Runnable... runnables){&nbsp; &nbsp; CompletableFuture.supplyAsync(Runnables.trying(runnables));}

万千封印

您可以通过使用CompletableFuture.thenApply方法来获得所需的行为。例如:public class Answer {  public static void main(String[] args) {    Function<Integer, Integer> fn0 = v -> v + 5;    Function<Integer, Integer> fn1 = v -> {        throw new RuntimeException("failed");    };    Function<Integer, Integer> fn2 = v -> {        System.out.println("Reached last function !");        return v;    };    CompletableFuture.supplyAsync(() -> fn0.apply(100))            .thenApply(fn1)            .thenApply(fn2)            .exceptionally(throwable -> {                // next line prints the exception thrown by fn1, wrapped in java.util.concurrent.CompletionException                System.out.println("Failed with error: " + throwable);                 return 0; // default value, used when exception is thrown            });  }}基本上,CompletableFuture链将被“开箱即用”的异常中断,因此不需要额外的处理。或者,如果您想要更通用的方法:public class Answer {  public static void main(String[] args) {    executeAsync(() -> stepOne(100))            .thenApply(Answer::stepTwo)            .thenApply(Answer::finalStep)            .exceptionally(Answer::handleException);  }  private static CompletableFuture<Integer> executeAsync(Supplier<Integer> task) {    return CompletableFuture.supplyAsync(task::get);  }  private static Integer stepOne(Integer value) {    return value + 5;  }  private static Integer stepTwo(Integer value) {    throw new RuntimeException("failed");  }  private static Integer finalStep(Integer value) {    System.out.println("Reached last function !");    return value;  }  private static Integer handleException(Throwable throwable) {    // next line prints the exception thrown by any step before, wrapped in java.util.concurrent.CompletionException    System.out.println("Failed with error: " + throwable);    return 0; // default value  }笔记:使用thenApply您可以根据需要链接任意数量的函数调用在最后一个示例中,同一类中的方法可以替换为其他类中的方法(不一定是静态类)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java