Renaming Future.failure to Future.recover
This commit is contained in:
parent
3d7a717b06
commit
b0952e5212
4 changed files with 39 additions and 43 deletions
|
|
@ -146,30 +146,30 @@ class FutureSpec extends JUnitSuite {
|
||||||
val future2 = future1 map (_ / 0)
|
val future2 = future1 map (_ / 0)
|
||||||
val future3 = future2 map (_.toString)
|
val future3 = future2 map (_.toString)
|
||||||
|
|
||||||
val future4 = future1 failure {
|
val future4 = future1 recover {
|
||||||
case e: ArithmeticException ⇒ 0
|
case e: ArithmeticException ⇒ 0
|
||||||
} map (_.toString)
|
} map (_.toString)
|
||||||
|
|
||||||
val future5 = future2 failure {
|
val future5 = future2 recover {
|
||||||
case e: ArithmeticException ⇒ 0
|
case e: ArithmeticException ⇒ 0
|
||||||
} map (_.toString)
|
} map (_.toString)
|
||||||
|
|
||||||
val future6 = future2 failure {
|
val future6 = future2 recover {
|
||||||
case e: MatchError ⇒ 0
|
case e: MatchError ⇒ 0
|
||||||
} map (_.toString)
|
} map (_.toString)
|
||||||
|
|
||||||
val future7 = future3 failure { case e: ArithmeticException ⇒ "You got ERROR" }
|
val future7 = future3 recover { case e: ArithmeticException ⇒ "You got ERROR" }
|
||||||
|
|
||||||
val actor = actorOf[TestActor].start()
|
val actor = actorOf[TestActor].start()
|
||||||
|
|
||||||
val future8 = actor !!! "Failure"
|
val future8 = actor !!! "Failure"
|
||||||
val future9 = actor !!! "Failure" failure {
|
val future9 = actor !!! "Failure" recover {
|
||||||
case e: RuntimeException ⇒ "FAIL!"
|
case e: RuntimeException ⇒ "FAIL!"
|
||||||
}
|
}
|
||||||
val future10 = actor !!! "Hello" failure {
|
val future10 = actor !!! "Hello" recover {
|
||||||
case e: RuntimeException ⇒ "FAIL!"
|
case e: RuntimeException ⇒ "FAIL!"
|
||||||
}
|
}
|
||||||
val future11 = actor !!! "Failure" failure { case _ ⇒ "Oops!" }
|
val future11 = actor !!! "Failure" recover { case _ ⇒ "Oops!" }
|
||||||
|
|
||||||
assert(future1.get === 5)
|
assert(future1.get === 5)
|
||||||
intercept[ArithmeticException] { future2.get }
|
intercept[ArithmeticException] { future2.get }
|
||||||
|
|
@ -269,7 +269,7 @@ class FutureSpec extends JUnitSuite {
|
||||||
def receiveShouldExecuteOnComplete {
|
def receiveShouldExecuteOnComplete {
|
||||||
val latch = new StandardLatch
|
val latch = new StandardLatch
|
||||||
val actor = actorOf[TestActor].start()
|
val actor = actorOf[TestActor].start()
|
||||||
actor !!! "Hello" receive { case "World" ⇒ latch.open }
|
actor !!! "Hello" onResult { case "World" ⇒ latch.open }
|
||||||
assert(latch.tryAwait(5, TimeUnit.SECONDS))
|
assert(latch.tryAwait(5, TimeUnit.SECONDS))
|
||||||
actor.stop()
|
actor.stop()
|
||||||
}
|
}
|
||||||
|
|
@ -304,13 +304,13 @@ class FutureSpec extends JUnitSuite {
|
||||||
val latch = new StandardLatch
|
val latch = new StandardLatch
|
||||||
val f2 = Future { latch.tryAwait(5, TimeUnit.SECONDS); "success" }
|
val f2 = Future { latch.tryAwait(5, TimeUnit.SECONDS); "success" }
|
||||||
f2 foreach (_ ⇒ throw new ThrowableTest("dispatcher foreach"))
|
f2 foreach (_ ⇒ throw new ThrowableTest("dispatcher foreach"))
|
||||||
f2 receive { case _ ⇒ throw new ThrowableTest("dispatcher receive") }
|
f2 onResult { case _ ⇒ throw new ThrowableTest("dispatcher receive") }
|
||||||
val f3 = f2 map (s ⇒ s.toUpperCase)
|
val f3 = f2 map (s ⇒ s.toUpperCase)
|
||||||
latch.open
|
latch.open
|
||||||
f2.await
|
f2.await
|
||||||
assert(f2.resultOrException === Some("success"))
|
assert(f2.resultOrException === Some("success"))
|
||||||
f2 foreach (_ ⇒ throw new ThrowableTest("current thread foreach"))
|
f2 foreach (_ ⇒ throw new ThrowableTest("current thread foreach"))
|
||||||
f2 receive { case _ ⇒ throw new ThrowableTest("current thread receive") }
|
f2 onResult { case _ ⇒ throw new ThrowableTest("current thread receive") }
|
||||||
f3.await
|
f3.await
|
||||||
assert(f3.resultOrException === Some("SUCCESS"))
|
assert(f3.resultOrException === Some("SUCCESS"))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -320,14 +320,6 @@ sealed trait Future[+T] {
|
||||||
*/
|
*/
|
||||||
def await(atMost: Duration): Future[T]
|
def await(atMost: Duration): Future[T]
|
||||||
|
|
||||||
/**
|
|
||||||
* Blocks the current thread until the Future has been completed. Use
|
|
||||||
* caution with this method as it ignores the timeout and will block
|
|
||||||
* indefinitely if the Future is never completed.
|
|
||||||
*/
|
|
||||||
@deprecated("Will be removed after 1.1, it's dangerous and can cause deadlocks, agony and insanity.", "1.1")
|
|
||||||
def awaitBlocking: Future[T]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests whether this Future has been completed.
|
* Tests whether this Future has been completed.
|
||||||
*/
|
*/
|
||||||
|
|
@ -383,17 +375,35 @@ sealed trait Future[+T] {
|
||||||
* When the future is completed with a valid result, apply the provided
|
* When the future is completed with a valid result, apply the provided
|
||||||
* PartialFunction to the result.
|
* PartialFunction to the result.
|
||||||
* <pre>
|
* <pre>
|
||||||
* val result = future receive {
|
* val result = future onResult {
|
||||||
* case Foo => "foo"
|
* case Foo => "foo"
|
||||||
* case Bar => "bar"
|
* case Bar => "bar"
|
||||||
* }.await.result
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
final def receive(pf: PartialFunction[Any, Unit]): Future[T] = onComplete { f ⇒
|
final def onResult(pf: PartialFunction[Any, Unit]): Future[T] = onComplete { f ⇒
|
||||||
val optr = f.result
|
val optr = f.result
|
||||||
if (optr.isDefined) {
|
if (optr.isDefined) {
|
||||||
val r = optr.get
|
val r = optr.get
|
||||||
if (pf.isDefinedAt(r)) pf(r)
|
if (pf isDefinedAt r) pf(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the future is completed with an exception, apply the provided
|
||||||
|
* PartialFunction to the exception.
|
||||||
|
* <pre>
|
||||||
|
* val result = future onException {
|
||||||
|
* case Foo => "foo"
|
||||||
|
* case Bar => "bar"
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
final def onException(pf: PartialFunction[Throwable, Unit]): Future[T] = onComplete { f ⇒
|
||||||
|
val opte = f.exception
|
||||||
|
if (opte.isDefined) {
|
||||||
|
val e = opte.get
|
||||||
|
if (pf isDefinedAt e) pf(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,12 +449,12 @@ sealed trait Future[+T] {
|
||||||
* a valid result then the new Future will contain the same.
|
* a valid result then the new Future will contain the same.
|
||||||
* Example:
|
* Example:
|
||||||
* <pre>
|
* <pre>
|
||||||
* Future(6 / 0) failure { case e: ArithmeticException => 0 } // result: 0
|
* Future(6 / 0) recover { case e: ArithmeticException => 0 } // result: 0
|
||||||
* Future(6 / 0) failure { case e: NotFoundException => 0 } // result: exception
|
* Future(6 / 0) recover { case e: NotFoundException => 0 } // result: exception
|
||||||
* Future(6 / 2) failure { case e: ArithmeticException => 0 } // result: 3
|
* Future(6 / 2) recover { case e: ArithmeticException => 0 } // result: 3
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
final def failure[A >: T](pf: PartialFunction[Throwable, A]): Future[A] = {
|
final def recover[A >: T](pf: PartialFunction[Throwable, A]): Future[A] = {
|
||||||
val fa = new DefaultPromise[A](timeoutInNanos, NANOS)
|
val fa = new DefaultPromise[A](timeoutInNanos, NANOS)
|
||||||
onComplete { ft ⇒
|
onComplete { ft ⇒
|
||||||
val opte = ft.exception
|
val opte = ft.exception
|
||||||
|
|
@ -708,18 +718,6 @@ class DefaultPromise[T](timeout: Long, timeunit: TimeUnit) extends Promise[T] {
|
||||||
else throw new FutureTimeoutException("Futures timed out after [" + NANOS.toMillis(timeoutInNanos) + "] milliseconds")
|
else throw new FutureTimeoutException("Futures timed out after [" + NANOS.toMillis(timeoutInNanos) + "] milliseconds")
|
||||||
}
|
}
|
||||||
|
|
||||||
def awaitBlocking = {
|
|
||||||
_lock.lock
|
|
||||||
try {
|
|
||||||
while (_value.isEmpty) {
|
|
||||||
_signal.await
|
|
||||||
}
|
|
||||||
this
|
|
||||||
} finally {
|
|
||||||
_lock.unlock
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def isExpired: Boolean = timeLeft() <= 0
|
def isExpired: Boolean = timeLeft() <= 0
|
||||||
|
|
||||||
def value: Option[Either[Throwable, T]] = {
|
def value: Option[Either[Throwable, T]] = {
|
||||||
|
|
@ -816,7 +814,6 @@ sealed class KeptPromise[T](suppliedValue: Either[Throwable, T]) extends Promise
|
||||||
def onComplete(func: Future[T] ⇒ Unit): Future[T] = { func(this); this }
|
def onComplete(func: Future[T] ⇒ Unit): Future[T] = { func(this); this }
|
||||||
def await(atMost: Duration): Future[T] = this
|
def await(atMost: Duration): Future[T] = this
|
||||||
def await: Future[T] = this
|
def await: Future[T] = this
|
||||||
def awaitBlocking: Future[T] = this
|
|
||||||
def isExpired: Boolean = true
|
def isExpired: Boolean = true
|
||||||
def timeoutInNanos: Long = 0
|
def timeoutInNanos: Long = 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,6 @@ The 'Future' interface looks like this:
|
||||||
|
|
||||||
interface Future<T> {
|
interface Future<T> {
|
||||||
void await();
|
void await();
|
||||||
void awaitBlocking();
|
|
||||||
boolean isCompleted();
|
boolean isCompleted();
|
||||||
boolean isExpired();
|
boolean isExpired();
|
||||||
long timeoutInNanos();
|
long timeoutInNanos();
|
||||||
|
|
|
||||||
|
|
@ -238,12 +238,12 @@ Exceptions
|
||||||
|
|
||||||
Since the result of a ``Future`` is created concurrently to the rest of the program, exceptions must be handled differently. It doesn't matter if an ``Actor`` or the dispatcher is completing the ``Future``, if an ``Exception`` is caught the ``Future`` will contain it instead of a valid result. If a ``Future`` does contain an ``Exception``, calling ``get`` will cause it to be thrown again so it can be handled properly.
|
Since the result of a ``Future`` is created concurrently to the rest of the program, exceptions must be handled differently. It doesn't matter if an ``Actor`` or the dispatcher is completing the ``Future``, if an ``Exception`` is caught the ``Future`` will contain it instead of a valid result. If a ``Future`` does contain an ``Exception``, calling ``get`` will cause it to be thrown again so it can be handled properly.
|
||||||
|
|
||||||
It is also possible to handle an ``Exception`` by returning a different result. This is done with the ``failure`` method. For example:
|
It is also possible to handle an ``Exception`` by returning a different result. This is done with the ``recover`` method. For example:
|
||||||
|
|
||||||
.. code-block:: scala
|
.. code-block:: scala
|
||||||
|
|
||||||
val future = actor !!! msg1 failure {
|
val future = actor !!! msg1 recover {
|
||||||
case e: ArithmeticException => 0
|
case e: ArithmeticException => 0
|
||||||
}
|
}
|
||||||
|
|
||||||
In this example, if an ``ArithmeticException`` was thrown while the ``Actor`` processed the message, our ``Future`` would have a result of 0. The ``failure`` method works very similarly to the standard try/catch blocks, so multiple ``Exception``\s can be handled in this manner, and if an ``Exception`` is not handled this way it will be behave as if we hadn't used the ``failure`` method.
|
In this example, if an ``ArithmeticException`` was thrown while the ``Actor`` processed the message, our ``Future`` would have a result of 0. The ``recover`` method works very similarly to the standard try/catch blocks, so multiple ``Exception``\s can be handled in this manner, and if an ``Exception`` is not handled this way it will be behave as if we hadn't used the ``recover`` method.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue