我的同事们偏爱的Java 8编码风格是通过链接异步调用,例如
CompletionStage<E> someMethod() {
return doSomething().thenCompose(a -> {
// ...
return b;
}).thenCompose(b -> {
// ...
return c;
}).thenCompose(c -> {
// ...
return d;
}).thenApply(d -> {
// ...
return e;
});
}
我有类似上述的东西,但增加了一个挑战:我需要在后面的 lambda 中调用获取到的某些 lambda 中的值。例如,
CompletionStage<E> someMethod() {
return doSomething().thenCompose(a -> {
// ...
Foo foo = fooDAO.getFoos(a);
// ...
return b;
}).thenCompose(b -> {
// ...
return c;
}).thenCompose(c -> {
// ...
Bar bar = barDAO.getBars(foo);
// ...
return d;
}).thenApply(d -> {
// ...
return someResult(d, bar);
});
}
当我在外部作用域中声明Foo foo;
和Bar bar;
时,我会收到关于它们不是最终或有效最终的错误。我读到使用包装器使它们有效最终,但对我来说这似乎有些hacky(诡异),我不明白为什么允许这样做...
我读到Java 8没有添加对元组的支持(尽管它考虑了BiVal
,也许我可以将其用于传递给BiFunction
lambda)。所以我尝试使用一对(例如)
return doSomething().thenCompose(a -> {
// ...
Foo foo = fooDAO.getFoos(a);
// ...
return new Pair<>(foo, b);
}).thenCompose(fooAndB -> {
然后无论我在哪里需要回忆foo
,
Foo foo = fooAndB.getKey();
但这感觉语义上是错误的。而且它不起作用!我不知道为什么,因为我认为lambda参数的作用域与其外部作用域相同,所以所有lambda参数都可以从后续链接的lambda中访问。
lambda参数的真正作用域是什么?在保持链接的同时,是否有一种惯用或至少语义上无害的方法来完成我想做的事情?
基于打破链式结构的答案也可以,因为它们可能对未来的观众有用,但在我的情况下,偏离代码库中主导风格可能会导致拖延的PR会话和延迟的批准,因此我希望有一个保留链接的解决方案。或者,解释或演示保持链接会有多疯狂。谢谢!
AtomicReference<Foo>
,然后使用get
方法获取当前值。 - Hadi JAtomicReference
。如果我能理解包装器所做的使编译器突然满意的差异,那么我就可以接受它...没有包装器的限制的目的是什么? - Andrew CheongAtomicReference
的内容帮助我理解了如果没有正确地将变量包装在外部范围中会出现的并发问题。正是因为我找到的包装器只是一个只有一个元素的数组,所以我觉得这种策略有些巧妙。 - Andrew Cheong