我正在尝试避免在将2个独立的组合与返回第三个的CompletableFuture
组合时嵌套BiFunction
。
目前,使用thenCombine()
不会削减它:
// What I have
public CompletableFuture<CompletableFuture<C>> doStuff() {
CompletableFuture<A> aFuture = makeSomeA();
CompletableFuture<B> bFuture = makeSomeB();
CompletableFuture<CompletableFuture<C>> cFuture = aFuture.thenCombine(bFuture, this::makeSomeC);
return cFuture;
}
// What I want
public CompletableFuture<C> doStuff() {
CompletableFuture<A> aFuture = makeSomeA();
CompletableFuture<B> bFuture = makeSomeB();
// obv this method does not exist
CompletableFuture<C> c = aFuture.thenBicompose(bFuture, this::makeSomeC);
}
private CompletableFuture<A> makeSomeA() {...}
private CompletableFuture<B> makeSomeB() {...}
private CompletableFuture<C> makeSomeC(A a, B b) {...}
如果有一个CompletableFuture
monad,我基本上试图找到一种看起来像haskell的方式:
doStuff :: CompletableFuture C
doStuff = do
a <- makeSomeA
b <- makeSomeB
makeSomeC a b
makeSomeA :: CompletableFuture A
makeSomeB :: CompletableFuture B
makeSomeC :: A -> B -> CompletableFuture C
我在某处读到join()
是可完成未来的flatMap
,所以我想我可以使用这种方法做aFuture.thenCombine(bFuture, ((Function<CompletableFuture<C>,C>) CompletableFuture::join).compose(this::makeSomeC)
这样的事情,但我不确定这是不是正确的/建议的方式去。而且我不能说这有助于以任何方式提供可读性......
答案 0 :(得分:7)
对我而言,thenCompose
似乎是Haskell Monad.bind
的直接等价物。
thenCompose
可以与Haskell monad绑定相同的方式嵌套,这也是Haskell中do-expression的结果。使用它可以解决您的问题:
public CompletableFuture<C> doStuff() {
CompletableFuture<A> aFuture = makeSomeA();
CompletableFuture<B> bFuture = makeSomeB();
return aFuture.thenCompose(a -> bFuture.thenCompose(b -> makeSomeC(a, b)));
}
通过检查函数的类型可以看出这一点。
Monad绑定 - 在Haskell中写入>>=
- 具有以下类型:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Java中的 thenCompose
具有以下签名:
public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)
以上转换为Haskell语法,附加参数为显式this
,如下所示:
thenCompose :: CompletionStage T -> (T -> CompletionStage U) -> CompletionStage U
我们可以看到它具有与Haskell类型相同的结构。区别在于名称,而且Haskell对更高级别的支持的事实并不完全由Java接口表达。
但我对你的Haskell代码感到有些困惑。对我来说,看起来你的Haskell代码正在执行以下操作:
public CompletableFuture<C> doStuff() {
return makeSomeA().thenCompose(a -> makeSomeB().thenCompose(b -> makeSomeC(a, b)));
}
也就是说,等到makeSomeA
操作完成后再开始makeSomeB
。另一方面,Java代码并行启动两个操作,然后在C开始之前等待结果。但也许这是一个懒惰的事情。
答案 1 :(得分:6)
我想最简单的解决方案就是之后应用Exception : System.NullReferenceException: Object reference not
set to an instance of an object.
at Microsoft.ConfigurationManagement.PowerShell.Prov
ider.CMDriveProvider.NewItem(String path, String
itemTypeName, Object newItemValue)
at System.Management.Automation.SessionStateInternal
.NewItemPrivate(CmdletProvider providerInstance,
String path, String type, Object content,
CmdletProviderContext context)
TargetObject :
CategoryInfo : NotSpecified: (:) [New-Item], NullReferenceException
FullyQualifiedErrorId : System.NullReferenceException,Microsoft.PowerShell.Comm
ands.NewItemCommand
ErrorDetails :
InvocationInfo : System.Management.Automation.InvocationInfo
ScriptStackTrace : at set-drvsource, C:\temp\quick
import_cli-1.1\quickimport_cli-1.1\Invoke-QuickImport.p
s1: line 51
at main, C:\temp\quickimport_cl
i-1.1\quickimport_cli-1.1\Invoke-QuickImport.ps1: line
101
at <ScriptBlock>, C:\temp\quick
import_cli-1.1\quickimport_cli-1.1\Invoke-QuickImport.p
s1: line 165
PipelineIterationInfo : {}
PSMessageDetails :
:
thenCompose(identity())
或者,引入一个简单的public CompletableFuture<C> doStuff() {
CompletableFuture<A> aFuture = makeSomeA();
CompletableFuture<B> bFuture = makeSomeB();
CompletableFuture<CompletableFuture<C>> cFuture = aFuture.thenCombine(bFuture, this::makeSomeC);
return cFuture.thenCompose(Function.identity());
}
类来组合A和B的结果并使用Pair
:
thenCompose()
没有public CompletableFuture<C> doStuff() {
CompletableFuture<A> aFuture = makeSomeA();
CompletableFuture<B> bFuture = makeSomeB();
CompletableFuture<Pair<A, B>> cFuture = aFuture.thenCombine(bFuture, Pair::new);
return cFuture.thenCompose(p -> makeSomeC(p.a, p.b));
}
private static class Pair<A, B> {
A a;
B b;
public Pair(A a, B b) {
this.a = a;
this.b = b;
}
}
的第三种选择:
Pair