Escucha el futuro de Scala
future (2)
La segunda opción es la mejor, mantiene todo asíncrono. pero ... puedes hacer una mejor y abstraer la solución en un patrón reutilizable:
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
}
}
A continuación, puede simplemente llamar:
executor.asyncExecute(query).asScala
Estoy en el proceso de escribir un pequeño envoltorio de Scala alrededor de una biblioteca Java.
La biblioteca java tiene un objeto QueryExecutor que expone 2 métodos:
- ejecutar (consulta): Resultado
- asyncExecute (consulta): ListenableFuture [Resultado]
ListenableFuture en este contexto es el de la biblioteca de guayabas.
Quiero que mi contenedor de Scala devuelva un Future [Result] en lugar del objeto java, pero no estoy seguro de cuál es la mejor manera de implementarlo. Aquí hay 2 soluciones que se me ocurrieron:
future {
executor.execute(query)
}
y
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
Me pregunto qué método es el mejor. Mi intuición es que la primera, mientras devuelve un futuro, seguirá bloqueando un hilo mientras que la llamada para ejecutar espera una respuesta, la segunda parece que realmente no debería estar bloqueando. ¿Algún comentario sobre los pros / contras de cada método?
Otra solución ligeramente más corta:
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
}
}