Adding Java API for reduce, fold, apply and firstCompletedOf, adding << and apply() to CompletableFuture + a lot of docs
This commit is contained in:
parent
331f3e6469
commit
e23ba6e5bb
3 changed files with 112 additions and 0 deletions
|
|
@ -55,6 +55,13 @@ object Futures {
|
||||||
futureResult
|
futureResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java API
|
||||||
|
* Returns a Future to the result of the first future in the list that is completed
|
||||||
|
*/
|
||||||
|
def firstCompletedOf[T <: AnyRef](futures: java.lang.Iterable[Future[T]], timeout: Long): Future[T] =
|
||||||
|
firstCompletedOf(scala.collection.JavaConversions.asScalaIterable(futures),timeout)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A non-blocking fold over the specified futures.
|
* A non-blocking fold over the specified futures.
|
||||||
* The fold is performed on the thread where the last future is completed,
|
* The fold is performed on the thread where the last future is completed,
|
||||||
|
|
@ -95,6 +102,16 @@ object Futures {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java API
|
||||||
|
* A non-blocking fold over the specified futures.
|
||||||
|
* The fold is performed on the thread where the last future is completed,
|
||||||
|
* the result will be the first failure of any of the futures, or any failure in the actual fold,
|
||||||
|
* or the result of the fold.
|
||||||
|
*/
|
||||||
|
def fold[T <: AnyRef, R <: AnyRef](zero: R, timeout: Long, futures: java.lang.Iterable[Future[T]], fun: akka.japi.Function2[R, T, R]): Future[R] =
|
||||||
|
fold(zero, timeout)(scala.collection.JavaConversions.asScalaIterable(futures))( fun.apply _ )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates a fold over the supplied futures where the fold-zero is the result value of the Future that's completed first
|
* Initiates a fold over the supplied futures where the fold-zero is the result value of the Future that's completed first
|
||||||
*/
|
*/
|
||||||
|
|
@ -119,6 +136,13 @@ object Futures {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java API
|
||||||
|
* Initiates a fold over the supplied futures where the fold-zero is the result value of the Future that's completed first
|
||||||
|
*/
|
||||||
|
def reduce[T <: AnyRef, R >: T](futures: java.lang.Iterable[Future[T]], timeout: Long, fun: akka.japi.Function2[R, T, T]): Future[R] =
|
||||||
|
reduce(scala.collection.JavaConversions.asScalaIterable(futures), timeout)(fun.apply _)
|
||||||
|
|
||||||
import scala.collection.mutable.Builder
|
import scala.collection.mutable.Builder
|
||||||
import scala.collection.generic.CanBuildFrom
|
import scala.collection.generic.CanBuildFrom
|
||||||
|
|
||||||
|
|
@ -162,6 +186,10 @@ object Futures {
|
||||||
}
|
}
|
||||||
|
|
||||||
object Future {
|
object Future {
|
||||||
|
/**
|
||||||
|
* This method constructs and returns a Future that will eventually hold the result of the execution of the supplied body
|
||||||
|
* The execution is performed by the specified Dispatcher.
|
||||||
|
*/
|
||||||
def apply[T](body: => T, timeout: Long = Actor.TIMEOUT)(implicit dispatcher: MessageDispatcher): Future[T] = {
|
def apply[T](body: => T, timeout: Long = Actor.TIMEOUT)(implicit dispatcher: MessageDispatcher): Future[T] = {
|
||||||
val f = new DefaultCompletableFuture[T](timeout)
|
val f = new DefaultCompletableFuture[T](timeout)
|
||||||
dispatcher.dispatchFuture(FutureInvocation(f.asInstanceOf[CompletableFuture[Any]], () => body))
|
dispatcher.dispatchFuture(FutureInvocation(f.asInstanceOf[CompletableFuture[Any]], () => body))
|
||||||
|
|
@ -170,6 +198,23 @@ object Future {
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait Future[+T] {
|
sealed trait Future[+T] {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of this future after waiting for it to complete,
|
||||||
|
* this method will throw any throwable that this Future was completed with
|
||||||
|
* and will throw a java.util.concurrent.TimeoutException if there is no result
|
||||||
|
* within the Futures timeout
|
||||||
|
*/
|
||||||
|
def apply(): T = this.await.resultOrException match {
|
||||||
|
case None => throw new java.util.concurrent.TimeoutException("Future timed out!")
|
||||||
|
case s: Some[T] => s.get
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java API for apply()
|
||||||
|
*/
|
||||||
|
def get: T = apply()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks the current thread until the Future has been completed or the
|
* Blocks the current thread until the Future has been completed or the
|
||||||
* timeout has expired. In the case of the timeout expiring a
|
* timeout has expired. In the case of the timeout expiring a
|
||||||
|
|
@ -410,13 +455,43 @@ sealed trait Future[+T] {
|
||||||
* Essentially this is the Promise (or write-side) of a Future (read-side)
|
* Essentially this is the Promise (or write-side) of a Future (read-side)
|
||||||
*/
|
*/
|
||||||
trait CompletableFuture[T] extends Future[T] {
|
trait CompletableFuture[T] extends Future[T] {
|
||||||
|
/**
|
||||||
|
* Completes this Future with the specified result, if not already completed,
|
||||||
|
* returns this
|
||||||
|
*/
|
||||||
def complete(value: Either[Throwable, T]): CompletableFuture[T]
|
def complete(value: Either[Throwable, T]): CompletableFuture[T]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completes this Future with the specified result, if not already completed,
|
||||||
|
* returns this
|
||||||
|
*/
|
||||||
final def completeWithResult(result: T): CompletableFuture[T] = complete(Right(result))
|
final def completeWithResult(result: T): CompletableFuture[T] = complete(Right(result))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completes this Future with the specified exception, if not already completed,
|
||||||
|
* returns this
|
||||||
|
*/
|
||||||
final def completeWithException(exception: Throwable): CompletableFuture[T] = complete(Left(exception))
|
final def completeWithException(exception: Throwable): CompletableFuture[T] = complete(Left(exception))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completes this Future with the specified other Future, when that Future is completed,
|
||||||
|
* unless this Future has already been completed
|
||||||
|
* returns this
|
||||||
|
*/
|
||||||
final def completeWith(other: Future[T]): CompletableFuture[T] = {
|
final def completeWith(other: Future[T]): CompletableFuture[T] = {
|
||||||
other onComplete { f => complete(f.value.get) }
|
other onComplete { f => complete(f.value.get) }
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias for complete(Right(value))
|
||||||
|
*/
|
||||||
|
final def << (value: T): CompletableFuture[T] = complete(Right(value))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias for completeWith(other)
|
||||||
|
*/
|
||||||
|
final def << (other : Future[T]): CompletableFuture[T] = completeWith(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,13 @@ trait Function[T,R] {
|
||||||
def apply(param: T): R
|
def apply(param: T): R
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Function interface. Used to create 2-arg first-class-functions is Java (sort of).
|
||||||
|
*/
|
||||||
|
trait Function2[T1, T2, R] {
|
||||||
|
def apply(arg1: T1, arg2: T2): R
|
||||||
|
}
|
||||||
|
|
||||||
/** A Procedure is like a Function, but it doesn't produce a return value
|
/** A Procedure is like a Function, but it doesn't produce a return value
|
||||||
*/
|
*/
|
||||||
trait Procedure[T] {
|
trait Procedure[T] {
|
||||||
|
|
|
||||||
|
|
@ -324,4 +324,34 @@ class FutureSpec extends JUnitSuite {
|
||||||
// make sure all futures are completed in dispatcher
|
// make sure all futures are completed in dispatcher
|
||||||
assert(Dispatchers.defaultGlobalDispatcher.futureQueueSize === 0)
|
assert(Dispatchers.defaultGlobalDispatcher.futureQueueSize === 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test def shouldBlockUntilResult {
|
||||||
|
val latch = new StandardLatch
|
||||||
|
|
||||||
|
val f = Future({ latch.await; 5})
|
||||||
|
val f2 = Future({ f() + 5 })
|
||||||
|
|
||||||
|
assert(f2.resultOrException === None)
|
||||||
|
latch.open
|
||||||
|
assert(f2() === 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test def lesslessIsMore {
|
||||||
|
import akka.actor.Actor.spawn
|
||||||
|
val dataflowVar, dataflowVar2 = new DefaultCompletableFuture[Int](Long.MaxValue)
|
||||||
|
val begin, end = new StandardLatch
|
||||||
|
spawn {
|
||||||
|
begin.await
|
||||||
|
dataflowVar2 << dataflowVar
|
||||||
|
end.open
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn {
|
||||||
|
dataflowVar << 5
|
||||||
|
}
|
||||||
|
begin.open
|
||||||
|
end.await
|
||||||
|
assert(dataflowVar2() === 5)
|
||||||
|
assert(dataflowVar.get === 5)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue