Thursday, April 25, 2019

Scala - Catching Exceptions & Optional Values

Catching Exceptions

- No Checked Exception in Scala
- Use try-catch expressions to catch an exception
- In the catch clause - define one or more match alternatives
- The finally clause is optional. Scala provides a useful alternative Try

def toInt( s:String ) : Int = try {
     | s.toInt
     | } catch {
     | case _: NumberFormatException => 0
     | }


Using Try

- Try executes a given expression and returns true or failure

scala> import scala.util.{Try,Success,Failure}
import scala.util.{Try, Success, Failure}

scala> Try("100".toInt)
res60: scala.util.Try[Int] = Success(100)

scala> Try("Martin".toInt)
res61: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "Martin")


Pattern Matching on Try

- Use try in the same way as Option. One way is with Pattern Matching

scala> def makeInt(s:String): Int = Try(s.toInt) match {
     | case Success(n) => n
     | case Failure(_) => 0
     | }
makeInt: (s: String)Int

scala> makeInt("100")
res62: Int = 100

scala> makeInt("Hello")
res63: Int = 0


Higher Order Functions on Try

- getOrElse  extracts the wrapped value or returns the default
- Try offers Higher Order Functions known from collections

scala> def makeInt(s:String) = Try(s.toInt).getOrElse(0)
makeInt: (s: String)Int

scala> Success("scala").map(_.reverse)
res64: scala.util.Try[String] = Success(alacs)

scala> for {
     | lang <- Success("Scala")
     | behav <- Success("Rocks")
     | } yield s"$lang $behav"
res65: scala.util.Try[String] = Success(Scala Rocks)


Optional Values

The Option Class - It is an ADT with two possible types
- Some case class, wrapping a value
- None singleton object

scala> val langs = Map( "s" -> "Scala", "j" -> "Java"  )
langs: scala.collection.immutable.Map[String,String] = Map(s -> Scala, j -> Java)

scala> langs.get("s")
res41: Option[String] = Some(Scala)

scala> langs.get("c")
res42: Option[String] = None


Using Option Instances

Some and None can be used directly 

Some("Scala")
Option(null)

Pattern matching on Option

- The type system enforces us to handle an optional value
- One way is with Pattern matching

scala> def langsByFirst( s: String ): String = langs.get(s) match {
     | case Some(language) => language
     | case None => s"No language starting with $s"
     | }
langsByFirst: (s: String)String

scala> langsByFirst("s")
res47: String = Scala

scala> langsByFirst("c")
res48: String = No language starting with c


Higher Order Functions on Option

- Option offers higher order functions known from collections
- Using higher order functions such as map and flatmap on Option, allows to easily compose a chain of calls that handles missing values gracefully

scala> Option("Scala").map(_.reverse)
res49: Option[String] = Some(alacS)

scala> for {
     | lang <- Some("Scala")
     | behaviour <- Some("rocks")
     | } yield s"$lang $behaviour"
res53: Option[String] = Some(Scala rocks)

scala> val langs = Map("s" -> "Scala", "j" -> "Java")
langs: scala.collection.immutable.Map[String,String] = Map(s -> Scala, j -> Java)

- foreach calls a function only if a value is present

scala> langs.get("s").foreach(println)
Scala

scala> langs.get("c").foreach(println)


Obtaining the value 

- The getOrElse extracts the wrapped value or returns a default

scala> def langsByFirst(s:String): String = langs.get(s).getOrElse(s"No langs starting with $s")
langsByFirst: (s: String)String

scala> langsByFirst("c")
res56: String = No langs starting with c

No comments:

Post a Comment