CompletableFuture 的 whenComplete 签名
Signature of whenComplete from CompletableFuture
有谁知道将 java CompletableFuture
的 whenComplete
方法翻译成 Scala 吗?我真的不知道该怎么做,我有点卡住了。谢谢
这是一个向您展示它如何工作的示例(在 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 秒的未来,然后完成返回一个字符串值。 (另请参阅下面解释其工作原理的说明。)
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]
现在在 future 完成时执行一些代码。 (您应该从这里开始您自己的 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]
(请注意,在这种情况下,future 在我能够输入 whenComplete
方法之前完成。这显然是一个竞争条件,因此如果您立即将整个批次粘贴到 REPL ,你可能会看到 res0
被确定为有 "Not completed",然后看到 whenComplete
函数的输出。)
那么这里发生了什么,因为这段代码看起来不太像相关 classes 的 JavaDoc?
这是一个名为 single abstract methods 的 Scala 魔术。本质上,如果 asbtract class(或特征)有一个抽象方法,那么您可以用抽象方法的定义替换那个 class 的实例。此外,Scala 从关联函数的参数列表中知道哪个 class 是相关的。
让我们从 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]
有一个 单一抽象方法 、get
,编译器能够接受使用 函数文字 的缩写形式作为 Supplier
及其 get
方法。
然后我们使用与 whenComplete
方法相同的方法。这里,参数的类型是一个 BiConsumer[T, U]
(其中 T
是 future 返回值的类型,U
是一个异常类型),它接受一个 单个抽象方法 accept
。 (这种类型也有一个 andThen
方法,但那不是抽象的,所以它对 Scala 无关紧要。)所以,为了更明确,我们可以写成以下:
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]
两种方法都有效,所以请随意使用对您有意义的一种...
请注意,whenComplete
比传统的 Scala 代码更丑 很多 代码通常需要:如果未来抛出异常成功完成,那么error
将是非null
;否则,result
将包含未来的结果,也可能是 null
.
如果可能的话,我强烈建议改用 Scala Future
s。比 Java.
中的功能更实用,也更优雅
您可以使用以下命令将 Java CompletableFuture
转换为 Scala Future
隐式转换:
import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.language.implicitConversion
import scala.util.{Failure, Success}
implicit def completableFutureToFuture[T](cf: CompletableFuture[T]): Future[T] = {
val p = Promise[T]() // Promise monitoring result of java cf.
// Handle completion of Java future.
cf.whenComplete {(result, error) =>
// If error is not null, then future failed.
if(error ne null) p.failure(error)
// Otherwise, it succeeded with result.
else p.success(result)
}
// Return the Scala future associated with the promise.
p.future
}
然后您可以更优雅地处理 Java 未来的完成(同样,在 REPL 中,具有上述定义):
scala> val scalaFuture = future // Implicit conversion called.
scalaFuture: scala.concurrent.Future[String] = Future(Success(We done did it!))
scala> scalaF.onComplete {
| case Success(s) => println(s"Succeeded with '$s'")
| case Failure(e) => println(s"Failed with '$e'...")
| }
有谁知道将 java CompletableFuture
的 whenComplete
方法翻译成 Scala 吗?我真的不知道该怎么做,我有点卡住了。谢谢
这是一个向您展示它如何工作的示例(在 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 秒的未来,然后完成返回一个字符串值。 (另请参阅下面解释其工作原理的说明。)
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]
现在在 future 完成时执行一些代码。 (您应该从这里开始您自己的 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]
(请注意,在这种情况下,future 在我能够输入 whenComplete
方法之前完成。这显然是一个竞争条件,因此如果您立即将整个批次粘贴到 REPL ,你可能会看到 res0
被确定为有 "Not completed",然后看到 whenComplete
函数的输出。)
那么这里发生了什么,因为这段代码看起来不太像相关 classes 的 JavaDoc?
这是一个名为 single abstract methods 的 Scala 魔术。本质上,如果 asbtract class(或特征)有一个抽象方法,那么您可以用抽象方法的定义替换那个 class 的实例。此外,Scala 从关联函数的参数列表中知道哪个 class 是相关的。
让我们从 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]
有一个 单一抽象方法 、get
,编译器能够接受使用 函数文字 的缩写形式作为 Supplier
及其 get
方法。
然后我们使用与 whenComplete
方法相同的方法。这里,参数的类型是一个 BiConsumer[T, U]
(其中 T
是 future 返回值的类型,U
是一个异常类型),它接受一个 单个抽象方法 accept
。 (这种类型也有一个 andThen
方法,但那不是抽象的,所以它对 Scala 无关紧要。)所以,为了更明确,我们可以写成以下:
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]
两种方法都有效,所以请随意使用对您有意义的一种...
请注意,whenComplete
比传统的 Scala 代码更丑 很多 代码通常需要:如果未来抛出异常成功完成,那么error
将是非null
;否则,result
将包含未来的结果,也可能是 null
.
如果可能的话,我强烈建议改用 Scala Future
s。比 Java.
您可以使用以下命令将 Java CompletableFuture
转换为 Scala Future
隐式转换:
import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.language.implicitConversion
import scala.util.{Failure, Success}
implicit def completableFutureToFuture[T](cf: CompletableFuture[T]): Future[T] = {
val p = Promise[T]() // Promise monitoring result of java cf.
// Handle completion of Java future.
cf.whenComplete {(result, error) =>
// If error is not null, then future failed.
if(error ne null) p.failure(error)
// Otherwise, it succeeded with result.
else p.success(result)
}
// Return the Scala future associated with the promise.
p.future
}
然后您可以更优雅地处理 Java 未来的完成(同样,在 REPL 中,具有上述定义):
scala> val scalaFuture = future // Implicit conversion called.
scalaFuture: scala.concurrent.Future[String] = Future(Success(We done did it!))
scala> scalaF.onComplete {
| case Success(s) => println(s"Succeeded with '$s'")
| case Failure(e) => println(s"Failed with '$e'...")
| }