我正在围绕java库编写一个小的scala包装器。
java库有一个QueryExecutor对象,它暴露了两种方法:
此上下文中的ListenableFuture来自番石榴库。
我希望我的scala包装器返回Future [Result]而不是java对象,但我不确定实现它的最佳方法是什么。以下是我提出的两个解决方案:
future {
executor.execute(query)
}
和
val p = promise[Result]
val guavaFuture = executor.asyncExecute(query)
Futures.addCallback(guavaFuture, new FutureCallback[Result] {
def onFailure(t: Throwable) {
p.failure(t)
}
def onSuccess(result: Result) {
p.success(result)
}
})
p.future
我想知道哪种方法最好。我的直觉是第一个,当返回一个Future时,仍然会阻塞一个线程,而执行调用等待响应,第二个看起来应该是非阻塞。对每种方法的利弊有何评论?
答案 0 :(得分:45)
第二个选项是最好的,它可以保持所有异步。但是......你可以做得更好,并将解决方案抽象为可重用的模式:
implicit class RichListenableFuture[T](lf: ListenableFuture[T]) {
def asScala: Future[T] = {
val p = Promise[T]()
Futures.addCallback(lf, new FutureCallback[T] {
def onFailure(t: Throwable): Unit = p failure t
def onSuccess(result: T): Unit = p success result
})
p.future
}
}
然后您可以简单地致电:
executor.asyncExecute(query).asScala
答案 1 :(得分:1)
另一个更短的解决方案:
implicit class ListenableFutureDecorator[T](val f: ListenableFuture[T]) extends AnyVal {
def asScala(implicit e: Executor): Future[T] = {
val p = Promise[T]()
f.addListener(() => p.complete(Try(f.get())), implicitly[Executor])
p.future
}
}