什么是CompletableFuture中与Streams的peek()方法相对应的方法?

4
这里的一个回答引用了所有CompletableFuture方法的表格,但不完全是我要找的,或者说我可能在错误的方向上寻找。
我正在寻找CompletableFuture中与Streams的peek()相当的方法,基本上是返回输入参数的thenApply,或者是不返回VoidthenRun。我可以想到两种方式,两种方式都不太准确地表达了我的意图,但却能实现目标:
(..)
.thenApply((a) -> {
   doSomething();
   return a;
}
(..)

并且

(..)
.whenComplete((result, exception) -> {
   if (exception == null) {
      doSomething();
   }
}
(..)

这两种方法都使用前一阶段的输入,让我执行一个操作,并返回相同类型的内容到下一阶段。其中后一种方法限制了我的时序,只有在所有其他操作完成之后才能进行,而不是异步地在前一个必要阶段完成后立即进行。

我也一直在寻找一个将消费函数作为参数的身份函数,但好像我必须自己编写它:

public static <T> Function<T, T> identityConsumer(Consumer<T> c) {
    return a -> { c.accept(a); return a; };
}

(..)
.thenApply(identityConsumer(a -> doSomething()));
(..)

除了编写自己的实用函数外,是否有一种优雅的方法在中间阶段执行操作,而无需返回任何内容,同时保持阶段的当前类型?

2
“第二种方法限制了我的时间,只有在所有其他事情完成后才能进行,而不是在前一个必要阶段完成后立即异步进行。” - 我真的不明白你在这里的意思,“所有其他事情”是什么?两者将在同一时刻调用(嗯,除非thenApply()在异常情况下不会被调用)。 whenComplete()似乎正是你要找的。 - Didier L
哦,我原以为在 whenComplete 之后不能再接 then。然而,whenComplete 强制我显式处理异常情况,这不是我现阶段想要的。 - Benny Bottema
如果你想要一个等价于 peek() 的方法,你也应该处理异常,因为它们不会停止后续阶段的执行 - 与 Stream API 相反,在其中任何异常都会停止整个管道。无论如何,目前我们所拥有的解决方案都在这里提到了。 - Didier L
2个回答

1

我也想这样做,所以我自己写了一个包装器:

/** Converts a Consumer into an identity Function that passes through the input */
public static <T> Function<T, T> peek(Consumer<T> fn) {
    return (t) -> {
        fn.accept(t);
        return t;
    };
}

用法如下:

.thenApply(Functions.peek(SomeUtil::yourConsumerMethod));

0

Stream不同的是,您可以从单个future创建多个函数链,因此没有必要在一条调用链中完成所有操作。我会这样解决你的问题:

var f1 = CompletableFuture.supplyAsync(...);
f1.thenRun(() -> doSomething()); // this is your "peek"
var f2 = f1.thenApply(...); // continue your chain of operations here

2
这是一个很好的观点,我没有想过。然而,像这样打破链式结构有点违背流畅 API 的初衷。这可能是经典的 JDK 解决方案,但并不算是“优雅”的。 - Benny Bottema
但是你没有访问结果的权限,这就是窥视的目的。 更糟糕的是:这种方法不可靠!如果doSomething()需要更长时间/休眠,则它可能在f2完成之前无法完成,即它可能根本无法完成或者即使f2失败了,它也可能成功。不要这样做。@Nicole有一个更好的解决方案。 - rü-
在Nicole的解决方案和Stream.peek中,peek可以成功而next函数可能会失败。对于OP来说,操作顺序是否重要并不清楚,但如果确实重要,那么他们应该明确地建模。 - MikeFHay
我没有说清楚:我应该说的是,即使thenRun失败,第二个thenApply也会运行。 而且我认为操作顺序几乎总是相关的。例如,peek可以是验证...这是非常常见的用例。 - rü-

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接