来自CompletableFuture的whenComplete的签名

时间:2018-10-10 17:28:24

标签: java scala completable-future

有人知道将Java whenComplete的{​​{1}}方法转换为Scala吗?我真的不知道该怎么做,我有点卡住了。谢谢

1 个答案:

答案 0 :(得分:3)

这是一个示例,向您展示它如何工作(在scala REPL内部)...

$ scala
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_181).
Type in expressions for evaluation. Or try :help.

scala> import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletableFuture

创建一个等待5秒钟的Future,然后完成返回一个字符串值。 (另请参见下面的注释,说明其工作原理。)

scala> val future = CompletableFuture.supplyAsync {() =>
     |   Thread.sleep(5000) // Wait 5,000 ms (5 seconds).
     |   "We done did it!"
     | }
future: java.util.concurrent.CompletableFuture[String] = java.util.concurrent.CompletableFuture@5a466dd[Not completed]

现在,将来完成时将执行一些代码。 (这是您应该从自己的whenComplete实现开始的地方。)

scala> future.whenComplete {(result, error) =>
     |   println(s"Result was: '$result', error was: '$error'")
     | }
Result was 'We done did it!'; error was 'null'
res0: java.util.concurrent.CompletableFuture[String] = java.util.concurrent.CompletableFuture@3ea9a091[Completed normally]

(请注意,在这种情况下,将来是在我能够键入whenComplete方法之前完成的。这显然是一个竞争条件,因此,如果您将全部全部一次粘贴到REPL中,可能会看到res0被确定为“未完成”,然后看到whenComplete函数的输出。)

那么这是怎么回事,因为此代码与相关类的 JavaDoc 不太相似?

这是一种叫做 single abstract methods Scala魔术。本质上,如果一个抽象类(或特征)具有单个抽象方法,则可以用该抽象方法的定义替换该类的实例。此外, Scala 从关联函数的参数列表中知道哪个类是相关的。

让我们从CompletableFuture.supplyAsync开始,它只接受一个Supplier[T]参数。用 Scala 术语,这种类型看起来像这样:

trait Supplier[T] {
  def get(): T
}

所以我们可以这样写future元素的创建:

scala> import java.util.function.Supplier
import java.util.function.Supplier

scala> val future = CompletableFuture.supplyAsync {
     |   new Supplier[String] {
     |     override def get(): String = {
     |       Thread.sleep(5000) // Wait 5,000 ms (5 seconds).
     |       "We done did it!"
     |     }
     |   }
     | }
future: java.util.concurrent.CompletableFuture[String] = java.util.concurrent.CompletableFuture@35becbd4[Not completed]

因为 Scala 编译器知道supplyAsync使用Supplier[T],并且因为Supplier[T]具有单个抽象方法,所以{ {1}},编译器可以接受使用函数文字作为get及其Supplier方法的定义的缩写形式。

然后,我们对get方法使用相同的方法。在这里,参数的类型是whenComplete(其中BiConsumer[T, U]是Future返回的值的类型,而T是异常类型),它采用单个抽象方法 U。 (此类型也有一个accept方法,但这不是抽象方法,因此对 Scala 来说无关紧要。)因此,为了更加明确,我们可以编写以下代码:

andThen

这两种方法都是有效的,因此请随意使用对您有意义的任何一种方法...

请注意,scala> import java.util.function.BiConsumer scala> future.whenComplete { | new BiConsumer[String, Throwable] { | override def accept(result: String, error: Throwable): Unit = { | println(s"Result was: '$result', error was: '$error'") | } | } | } Result was 'We done did it!'; error was 'null' res0: java.util.concurrent.CompletableFuture[String] = java.util.concurrent.CompletableFuture@3ea9a091[Completed normally] 比常规的 Scala 代码通常要糟糕得多:如果将来抛出异常而不是成功完成,则{{1 }}将不是whenComplete;否则,error将包含未来的结果,也可能是null

如果可能的话,我强烈建议您使用 Scala result s。与 Java 中的功能相比,功能更强大,更优雅。

您可以通过以下隐式转换将 Java null转换为 Scala Future

CompletableFuture

然后,您可以更加优雅地处理 Java 的完成工作(同样,在REPL中,定义如上):

Future