将Java Future转换为Scala Future

spa*_*rkr 12 scala future scala-java-interop

我有一个Java Future对象,我想将其转换为Scala Future.看看jucFuture API,除了isDone方法之外我没有什么可以使用的.这是isDone方法阻止吗?

目前这就是我的想法:

val p = Promise()
if (javaFuture.isDone())
  p.success(javaFuture.get)
Run Code Online (Sandbox Code Playgroud)

有一个更好的方法吗?

pab*_*han 13

如何包装它(我假设这里有一个隐含的ExecutionContext):

val scalaFuture = Future {
    javaFuture.get
}
Run Code Online (Sandbox Code Playgroud)

编辑:

一个简单的轮询策略可能如下所示(java.util.Future => F):

def pollForResult[T](f: F[T]): Future[T] = Future {
    Thread.sleep(500)
    f
  }.flatMap(f => if (f.isDone) Future { f.get } else pollForResult(f))
Run Code Online (Sandbox Code Playgroud)

这将检查Java未来是否每500毫秒完成一次.显然,总阻塞时间与上面相同(向上舍入到最接近的500毫秒),但是这个解决方案将允许其他任务在相同的线程中交错ExecutionContext.

  • 它可能没问题,但重要的是要清楚线程阻塞的发生.这是不容忽视的,必须有意识地评估是否可以.最好是确保没有人得到这样的印象:将阻塞调用包装成"Future {...}"会神奇地删除任何阻塞. (9认同)
  • 这是事实,但是虽然这不会阻塞当前线程,但这仍然会阻止来自`ExecutionContext`线程池的线程. (6认同)
  • @RégisJean-Gilles当然,但不知道背景,我认为这个解决方案很好.唯一可以做的是轮询结果,但这可能是不必要的. (2认同)
  • @pablochan,投票对任何事情都有什么帮助?`Thread.sleep(500)` 以与阻塞 `javaFuture.get` 调用相同的方式阻塞同一个线程,不是吗? (2认同)

Xav*_*hot 11

从开始Scala 2.13,标准库包括scala.jdk.FutureConverters提供Java到Scala的CompletableFuture/Future隐式转换的标准库:

import scala.jdk.FutureConverters._

// val javaFuture = java.util.concurrent.CompletableFuture.completedFuture(12)
val scalaFuture = javaFuture.asScala
// scalaFuture: scala.concurrent.Future[Int] = Future(Success(12))
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这仅适用于“java.util.concurrent.CompletionStage”的子类型。它不适用于“java.util.concurrent.Future”。 (6认同)
  • FutureConverts 对 CompletableFuture 和 CompletionStage 类型进行操作,而不是对 Future 类型进行操作。你没有回答OP的问题。 (3认同)

San*_*dal 7

使用FutureConvertors(Scala中的内置实用程序)将Java Future转换为Scala Future。

考虑将Java Future [Int]转换为Scala Future [Int]的示例::

import java.util.concurrent.CompletableFuture
import scala.compat.java8.FutureConverters

val javaFuture: java.util.concurrent.Future[Int] = ??? 
// Some method call which returns Java's Future[Int]

val scalaFuture: Future[Int] = 
FutureConverters.toScala(CompletableFuture.supplyAsync(new Supplier[Int] {
      override def get(): Int = javaFuture.get 
    }))
Run Code Online (Sandbox Code Playgroud)

我们可以为任何自定义类型而不是Int做类似的事情。

  • 如果你有一个“CompletableFuture”,它们会很好。但是您提供的代码只是@pablochan 答案的一个毫无意义的复杂版本。 (2认同)

Ale*_*hin 6

对于现在阅读此问题的人,如果您使用的是 Scala 2.13 及更高版本,请使用:

import scala.jdk.FutureConverters._
Run Code Online (Sandbox Code Playgroud)

并转换使用 completableFuture.asScala

如果您使用的是 Scala 2.12 及以下版本,请使用

import scala.compat.java8.FutureConverters._
Run Code Online (Sandbox Code Playgroud)

并转换使用:toScala(completableFuture)completableFuture.toScala

此外,在 Scala 2.12 中,请确保您使用的是正确的工件:

org.scala-lang.modules:scala-java8-compat_2.12:0.9.0
Run Code Online (Sandbox Code Playgroud)

现在,如果由于某种原因你所拥有的实际上是 aFuture和 not CompletableFuture,这在当今应该是一种罕见的情况,请遵循这些答案中的第一个:Transform Java Future into a CompletableFuture

  • FutureConverts 对 CompletableFuture 和 CompletionStage 类型进行操作,而不是对 Future 类型进行操作。你没有回答OP的问题。 (2认同)