def testThrowException(number: Int): Future[Int] = {
if (number == 0) {
throw new Exception("number is 0")
else {
Future{1}
}
for the above function, if i call it with testThrowException(0), i can see the exception error message printed in console but if i do something like
def testThrowException(number: Int): Future[Int] = {
anotherFuture.map {
if (number == 0) {
throw new Exception("number is 0")
} else {
1
}
}
i am not able to see the exception printed in console but if i do testThrowException.onFailure, i can see the failure message, is there anything i did wrong here? why the exception is not printed out
Future
runs in a separate thread so throwing inside a Future
just crashes that thread whilst leaving the main thread running. For example,
object Hello extends App {
println(s"Starting in main thread called ${Thread.currentThread.getName}...")
Future(
throw new RuntimeException(s"I crashed separate thread called ${Thread.currentThread.getName}")
).andThen { case Failure(e) => println(e.getMessage) }
println("I made it!")
}
should output
Starting in main thread called run-main-e...
I made it!
I crashed separate thread called scala-execution-context-global-253
where we see it crashed separate thread named scala-execution-context-global-253
whilst the main thread run-main-e
kept running so I made it!
got printed just fine. On the other hand, the following example throws outside a Future
object Hello extends App {
println(s"Starting in main thread called ${Thread.currentThread.getName}...")
throw new RuntimeException(s"I crashed the main thread ${Thread.currentThread.getName}")
println("I made it!")
}
which outputs
Starting in main thread called run-main-d...
[error] (run-main-d) java.lang.RuntimeException: I crashed the main thread run-main-d
where we see main thread run-main-d
crashed before I made it!
could be printed.
The first function testThrowException
does not return a Future in the case that it gets a 0
as input. Therefore, the program keeps running until the exception appears.
However, as seen in the source code pasted below, the Future.map
always returns another future:
def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { // transform(f, identity)
val p = Promise[S]()
onComplete { v => p complete (v map f) }
p.future
}
Just defining a Future does not print out its results and it also does not print exceptions thrown. You would need to define the onSuccess
, onFailure
, or onComplete
to do so. However, if a print statement exists in the body of the Future, then it will execute:
def addOne(number: Int): Int = {
if (number == 0) {
// you can also print the exception instead of just throwing it.
throw new Exception("number is 0")
} else {
println("success")
1 + number
}
}
Future { addOne(1) } // scala.concurrent.Future[Int] = Future(Success(2))
// the above also prints "success"
Future { addOne(0) } // scala.concurrent.Future[Int] = Future(Failure(java.lang.Exception: number is 0))
// the above does not print anything unless the exception is printed before thrown in `addOne`
You can also use onComplete
, to handle both success and/or failure:
// prints "got error" plus the stack trace
- List item
Future {0}.map(addOne).onComplete {
case Success(value) => println(s"got $value")
case Failure(t) => println("got error: " + t.getStackTrace.mkString("\n"))
}
Note that the imports used were:
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
In the 1st example the exception is just that, a naked exception thrown when encountered. It's not significantly different from something like this.
def testThrowException(number: Int): Future[Int] = {
throw new Exception("BOOM!")
. . . //code to create a Future[Int]
The 2nd example throws an exception inside a Fututre
. The exception is wrapped in a Future
, causing it to fail. You won't see anything sent to the console but if you inspect the result value you should see what you're looking for.
res0: scala.concurrent.Future[Int] = Future(Failure(java.lang.Exception: number is 0))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With