Lesson 6: Error handling

Scala for Java Developers

  • Review of previous concepts
  • Scala Try
    • Regular try/catch
    • Composability
    • For-comprehensions
  • Exercise

Recap

What is pattern matching and how does it work?

def teacher(lesson: Int) = lesson match {
  case 1 => "Sonia"
  case 2 => "Povilas"
  case 3 => "Greg"
  case 4 => "Sonia"
  case 5 => "Greg"
  case 6 => "Povilas"
  case _ => "Can't predict the future"
}
sealed trait Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification

def notication(msg: Notification): String = msg match {
  case e: Email => e.title
  case s: SMS => s.message
}

Pattern matching

What is a for comprehension?

val prices = List(100, 500, 450, 199)

// for-comprehension filtering
val highPrices = for (price <- prices if price > 200) yield price

// higher-order filter
val highPrices2 = prices.filter(price => price > 200)
val maybePrices = List(Some(100), Some(500), None, Some(199))

val maybeHighPrices =
  for {
    maybePrice <- maybePrices
    price <- maybePrice
    if price > 200
  } yield price

val maybeHighPrices2 = maybePrices.flatMap(prices => prices.filter(price => price > 200))

Nested collections (flatMap)

Simple map

Error Handling in Scala

Traditional error handling

import java.net.URL

def parseURL(url: String): URL = new URL(url)

//traditional try/catch
def parseURL(url: String): URL = 
try {
    new URL(url)
} catch {
  case e: MalformedURLException => println("Oh noes, pls try harder")  
}
  • Scala supports traditional Java style try/catch
  • Not as good when trying to compose multiple calls

Functional Error handling

scala.util.Try

One of more functional and composable ways to handle errors and failures

Try structure

sealed abstract class Try[T] {...}

final case class Success[T](value: T)
  extends Try[T] {...}

final case class Failure[T](exception: Throwable)
  extends Try[T] {...}

Implements higher-order methods

  • map

  • flatMap

  • filter (withFilter)

  • ... and others

(spot the similarity to Option)

mapping

parseURL("http://hotels.com").map(_.getProtocol)
// results in Success("http")
import java.io.InputStream

def inputStreamForURL(url: String): Try[InputStream] = parseURL(url).flatMap { url =>
  Try(url.openConnection()).flatMap(connection => Try(connection.getInputStream))
}

flatMapping

filtering

parseURL("http://hotels.com").filter(url => url.getProtocol == "ftp")
//results in Failure(java.util.NoSuchElementException)
import java.io.InputStream

def inputStreamForURL(url: String): Try[InputStream] = parseURL(url).flatMap { url =>
  Try(url.openConnection()).flatMap(connection => Try(connection.getInputStream))
}
import java.io.InputStream

def inputStreamForURL2(url: String): Try[InputStream] = {
  for {
    parsedUrl <- parseURL(url)
    connection <- Try(parsedUrl.openConnection())
    inputStr <- Try(connection.getInputStream)
  } yield inputStr
}

Translation into for-comprehensions

for-comprehension version 

flatMap version

def parseURL(url: String): Try[URL] = Try(new URL(url))

val result = parseURL("http://www.hotels.com")

result match {
  case Success(url) => println(url)
  case Failure(e) => println(s"An error occurred: ${ex.getMessage}")
}

Consuming Try 

parseURL("garbage") recover {
  case e: MalformedURLException => "Please make sure to enter a valid URL"
  case _ => "An unexpected error has occurred. We are so sorry!"
}
// returns Success(Please make sure to enter a valid URL)

Matching on a failure with recover

Pattern Matching

Exercise

cd path/to/scala-for-java-devs
git stash
git pull
git checkout lesson6

./sbt test
  • 2 Exercises
  • Aim to finish at least one from ForComprehensions

Scala For Java Devs 6

By Povilas Lape

Scala For Java Devs 6

Scala course lesson 6

  • 117