簡體   English   中英

來自CompletableFuture的whenComplete的簽名

[英]Signature of whenComplete from CompletableFuture

有人知道將Java CompletableFuturewhenComplete方法轉換為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秒鍾的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實現開始的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不太相似?

這是一種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]具有單個抽象方法 get ,所以編譯器能夠接受使用功能文字作為Supplier及其定義的縮寫形式。 get方法。

然后,我們對whenComplete方法使用相同的方法。 在這里,參數的類型是BiConsumer[T, U] (其中TBiConsumer[T, U]返回的值的類型,而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 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'...")
     | }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM