I have the following lines of code...
val a = Future { Thread.sleep(10*1000); 42 }
val b = a.map(_ * 2)
After sometime when I check the value of b, I have the following getting printed.
scala.concurrent.Future[Int] = Future(Success(84))
Above, b's type is Future[Int]; but in the documentation, it says Future's apply method always returns Future(Try[T]). The documentation and the above example contradict. Can someone please help.
Please post your imports and the documentation you have referenced.
I think best parallel to understanding this is:
Try[T]
is like Option[T]
, Try[T]
is always Success[T](value: T)
or Failure[T](exception: Throwable)
, just like Option[T]
is always Some[T](value: T)
or None
It can also be helpful to use the Scala REPL for things like this. It allows you to easily see types.
I'm assuming you've done this:
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> import scala.util.{Failure, Success}
import scala.util.{Failure, Success}
Now you have your two lines:
scala> val a = Future { Thread.sleep(10*1000); 42 }
val a: scala.concurrent.Future[Int] = Future(<not completed>)
scala> val b = a.map(_ * 2)
val b: scala.concurrent.Future[Int] = Future(<not completed>)
As you can see the type of b
is still of scala.concurrent.Future[Int]
as it maps the result of a
, an Int
, which happens to be 42
, using the function (_: Int -> _ * 2):Int
.
And eventually:
scala> b
val res0: scala.concurrent.Future[Int] = Future(Success(84))
From this documentation of Scala Future
s :
Notice that the 84 you expected is wrapped in a
Success
, which is further wrapped in aFuture
. This is a key point to know: The value in aFuture
is always an instance of one of theTry
types:Success
orFailure
. Therefore, when working with the result of a future, use the usualTry
-handling techniques, or one of the other Future callback methods.
Finally, to extract the Try
from the future, either a Success
or a Failure
, from which we will get our result, or an error:
scala> b.onComplete {
| case Success(value) => println(s"Got the callback, value = $value")
| case Failure(e) => e.printStackTrace
| }
Got the callback, value = 84
You are mixing two things here. When you create a Future
, it is created using the apply function which is in the companion object of Future
:
def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] =
unit.map(_ => body)
So as long as the future is not completed, its type is Future[Int]
. Once the future completes, the result type will be Future[Try[Int]]
.
As stated on onComplete
documentation:
When this future is completed, either through an exception, or a value, apply the provided function.
Therefore when you printed the completed future, it already had the Success. If you will do the same experiment with a longer wait, and an uncompleted future you will see that its type is not yet success.
For example, the following code:
implicit val ec = scala.concurrent.ExecutionContext.global
val a = Future { Thread.sleep(10*1000); 42 }
println(a)
Await.result(a, Integer.MAX_VALUE.seconds)
println(a)
will output:
Future(<not completed>)
Future(Success(42))
You can see that example running here .
Let's now look at onComplete . The following code:
val a = Future { Thread.sleep(10*1000); 42 }
a.onComplete {
case Success(value) =>
println(value)
case Failure(exception) =>
println(exception)
}
val b = Future { throw new RuntimeException }
b.onComplete {
case Success(value) =>
println(value)
case Failure(exception) =>
println(exception)
}
Await.result(a, Integer.MAX_VALUE.seconds)
Await.result(b, Integer.MAX_VALUE.seconds)
Here we can see an example how to use onComplete
when a
should complete successfully, and b
should throw, and this is exactly what we get. The output is:
java.lang.RuntimeException
42
Because the throwingFuture is completed first, it is printed first.
The documentation says that a Future[B]
contains a Try[B]
, which is correct. I think you're getting confused by the toString
representation here: Future(Success(84))
is the textual representation of a Future[Int]
. For a Future[Try[Int]]
, you would have Future(Success(Success(84)))
as the textual representation.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.