Options, Try, Futures, oh my! You can go read all the various articles on how the semantics of these are similar. Here’s one, I highly recommend the cheat sheet as a reference, comes in handy. But here is a real world examples to help as well. I find myself very often needing to handle an error just to print out a log message. So I started out with the normal try/catch as in Java. It’s a bunch of brackets and kinda verbose.
Then once you switch to using futures, at some point you’ll end up forgetting to handle a failure, and your root cause will just be gone, you’ll waste a bunch of time, and then start putting onComplete, onFailure, or recover everywhere. At least that’s what I did, maybe I’m an idiot, and you are smarter.
Well, that’s just as verbose as the try/catch, even more so when you don’t want to handle one side of the equation. What you can do, and this is the same for Try or a Future, is use “.failed.map”. Like this:
Try (someStuffThatMightFail).failed.map(e => println(e.getMessage)).
This will invert the Try so that failed() returns you a Try[Throwable], you can then map over it to get your error. getOrElse() and things like this don’t work because you want the error, and they won’t give it to you. If you have no error, then the map(), won’t do anything, and you just go on about your business.
So much cleaner, here are some examples:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.concurrent.Future | |
import scala.util.{Failure, Success, Try} | |
import scala.concurrent.ExecutionContext.Implicits.global | |
def fail = throw new RuntimeException("error now") | |
def failInFuture() = Future { throw new RuntimeException("error in future") } | |
try { | |
fail | |
} catch { | |
case e: Exception => println(e.getMessage) | |
} | |
failInFuture().onComplete { | |
case Success(result) => | |
case Failure(t) => println("error reported in onComplete") | |
} | |
failInFuture().onFailure { | |
case e => println("error reported in onFailure") | |
} | |
failInFuture().recover { | |
case e => println("error reported in recover") | |
} | |
Try (fail).failed.map(e => println(e.getMessage)) | |
failInFuture().failed.map(e => println(e.getMessage)) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
scala> import scala.concurrent.Future | |
import scala.concurrent.Future | |
scala> import scala.util.{Failure, Success, Try} | |
import scala.util.{Failure, Success, Try} | |
scala> import scala.concurrent.ExecutionContext.Implicits.global | |
import scala.concurrent.ExecutionContext.Implicits.global | |
scala> | |
scala> def fail = throw new RuntimeException("error now") | |
fail: Nothing | |
scala> | |
scala> def failInFuture() = Future { throw new RuntimeException("error in future") } | |
failInFuture: ()scala.concurrent.Future[Nothing] | |
scala> | |
scala> try { | |
| fail | |
| } catch { | |
| case e: Exception => println(e.getMessage) | |
| } | |
error now | |
scala> | |
scala> failInFuture().onComplete { | |
| case Success(result) => | |
| case Failure(t) => println("error reported in onComplete") | |
| } | |
error reported in onComplete | |
scala> | |
scala> failInFuture().onFailure { | |
| case e => println("error reported in onFailure") | |
| } | |
error reported in onFailure | |
scala> | |
scala> failInFuture().recover { | |
| case e => println("error reported in recover") | |
| } | |
res24: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@bd1111a | |
error reported in recover | |
scala> | |
scala> | |
scala> Try (fail).failed.map(e => println(e.getMessage)) | |
error now | |
res25: scala.util.Try[Unit] = Success(()) | |
scala> failInFuture().failed.map(e => println(e.getMessage)) | |
error in future | |
res26: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@65753040 |