将Java Future转换为Scala Future

27

我有一个Java Future对象,我想转换成Scala Future。查看j.u.c.Future API文档,除了isDone方法,似乎没有其他可用的选项。这个isDone方法是否会阻塞程序?目前我在想:

val p = Promise()
if (javaFuture.isDone())
  p.success(javaFuture.get)

有更好的方式吗?

4个回答

26

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))

15
请注意,这仅适用于 java.util.concurrent.CompletionStage 的子类型。它不适用于 java.util.concurrent.Future - Daniel Bimschas
6
FutureConverts 操作的是 CompletableFuture 和 CompletionStage 类型,而不是 Future 类型。你没有回答提问者的问题。 - K. M

23

如果只是简单地包装一下(我假设这里有一个隐式的ExecutionContext)呢:

val scalaFuture = Future {
    javaFuture.get
}

编辑:

一个简单的轮询策略可以看起来像这样(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))

这将每500毫秒检查Java future是否完成。显然,总阻塞时间与上面相同(四舍五入到最近的500毫秒),但此解决方案将允许其他任务在ExecutionContext的同一线程中交错执行。


12
没错,虽然这不会阻塞当前线程,但它仍会阻塞来自“ExecutionContext”线程池的线程。 - Régis Jean-Gilles
2
@RégisJean-Gilles 当然,但不知道上下文,我认为这个解决方案很好。唯一可以做的其他事情就是轮询结果,但在这里可能是不必要的。 - pablochan
13
可能这样做没问题,但是清楚线程阻塞的情况很重要。这一点不能忽视,必须有意识地评估是否可以接受。最好确保没有人会认为将阻塞调用包装在Future {...}中会神奇地消除任何阻塞。 - Régis Jean-Gilles
2
@pablochan,轮询有什么帮助吗?Thread.sleep(500)会像阻塞的javaFuture.get调用一样阻塞同一线程,不是吗? - eddyP23
是的,sleep 会阻塞线程,但比 javaFuture.get 更可预测。一旦调用 get,线程就会被阻塞直到完成。如果相同的 ExecutionContext 用于其他任务,则可能会阻塞几个长时间运行的 Futures。我并不是说轮询比仅包装 Future 更好,但在某些情况下可能是有意义的。 - pablochan
显示剩余4条评论

13

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

import scala.jdk.FutureConverters._

使用completableFuture.asScala进行转换

如果您正在使用Scala 2.12及以下版本,请使用

import scala.compat.java8.FutureConverters._

并且可以使用以下方式进行转换:toScala(completableFuture)completableFuture.toScala

另外,在 Scala 2.12 中请确保您正在使用正确的构件:

org.scala-lang.modules:scala-java8-compat_2.12:0.9.0

如果由于某种原因,您手头的是 Future,而不是现在很少见的 CompletableFuture,请首先参考下面其中一个答案进行转换:将Java Future转换为CompletableFuture


4
FutureConverts操作的是CompletableFuture和CompletionStage类型,而不是Future类型。您没有回答原帖作者的问题。 - K. M

7
使用Scala内置工具FutureConvertors将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 
    }))

类似地,我们可以针对任何自定义类型而不是Int执行此操作。

3
如果您有一个"CompletableFuture",那么它们是很好的。但是,您提供的代码只是@pablochan答案的更加复杂且毫无意义的版本。 - Alexey Romanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接