Skip to content

Instantly share code, notes, and snippets.

@helena
Last active July 13, 2021 15:03
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save helena/4434689 to your computer and use it in GitHub Desktop.
Save helena/4434689 to your computer and use it in GitHub Desktop.
Try introduced in Scala 2.10.0
// Start by adding these
import scala.util.{ Try, Success, Failure }
/**
* Sample runs code that raises the exception:
* java.lang.ArithmeticException: / by zero
*/
object Sample {
def main(args: Array[String]): Unit = {
// Class Risky below is not guarding against division by zero,
// neither is the javaLike function so let's pass in
// a zero and see how they behave
val input = 0
/* Output so you can see the results */
println("javaLike [%d]" format javaLike(input))
val risky = new Risky(input)
println("one [%s]" format risky.one)
println("two [%s]" format risky.two)
println("three [%d]" format risky.three)
println("four [%d]" format risky.four)
println("five [%s]" format risky.five)
println("six [%s]" format risky.six)
println("seven [%s]" format risky.seven)
println("eight [%s]" format risky.eight)
}
/**
* We can test what type `e` is, and trigger a variety of behaviors
* log info about the error context and return a default or raise
* the exception up the stack but really all I want is some elegant
* fault tolerance without each developer having to implement what
* that might look like all over an application
*/
def javaLike(input: Int): Int = {
import util.control.NonFatal
try {
5 / input
} catch {
case _ ⇒ 5 / 5
}
}
}
class Risky(input: Int) {
val num = 5
/** Does not guard against blowing up. */
def calculation: Int = num / input
/** Imagine this is an acceptable alternative */
def fallback: Int = num / num
/**
* If the Try is successful returns a Some(value)
* else None. This is very clean and elegant.
*/
def one: Option[Int] = Try(calculation).toOption
/**
* Useful for an expensive recursion, to test the
* status of something for example, before proceeding.
*/
def two: Boolean = Try(calculation).isSuccess
/**
* Cleanly returns the successful outcome otherwise an alternative
*/
def three: Int = Try(calculation) getOrElse fallback
/**
* Parses a Try where if successful returns the result, otherwise
* you can get into a variety of handling based on the type
* of Exception in the Failure.
*/
def four: Int = Try(calculation) match {
case Success(v) ⇒ v
case Failure(_) ⇒ fallback
}
/* Now we get into the fun, integrating Try into function signatures.
These expose the Try for the caller to work with it directly. */
/**
* The one will expose the exception naturally.
*/
def five: Try[Int] = Try(calculation)
/**
* The one will not expose the exception if the fallback is successful.
*/
def six: Try[Int] = Try(calculation) orElse Try(fallback)
/**
* Very much like the java try catch. Possibly useful
* for more complicated work where the recover case could
* raise an exception as well but why not just do the line
* above, it is more elegant.
*/
def seven: Try[Int] = Try(calculation) recoverWith {
case _ ⇒ Try(fallback)
}
/**
* Similar to old school try catch clauses, and the above
* `recoverWith` but if you have to do this ask yourself first
* if you just have a design flaw and could do `orElse` instead.
*/
def eight: Try[Int] = Try(calculation) recover {
case i: ArithmeticException ⇒ fallback
case e ⇒ throw e
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment