Dealing with errors in Scala.
Simple foreach
type Blog = Int
type BlogArticle = Int
def findArticles(blog: Blog): Seq[BlogArticle] = if (blog < 2) Seq() else Range(1, blog)
val blogs: Seq[Blog] = Seq(1, 2, 3)
Seq(1, 2, 3).foreach(blog => findArticles(blog))
Seq(1, 2, 3).foreach(blog => findArticles(blog).foreach(identity))
Can be written with for comprehension
for(blog <- blogs) {
findArticles(i)
}
for {
blog <- blogs
article <- findArticles(blog)
} {
identity(article)
}
Similar with map and flatMap
blogs.flatMap(blog => findArticles(blog).map(identity))
for {
blog <- blogs
article <- findArticles(blog)
} yield {
identity(article)
}
Even filtering possible
blogs.flatMap(blog => findArticles(blog).withFilter(_ == 1).map(identity))
for {
blog <- blogs
article <- findArticles(blog)
if article == 1
} yield {
identity(article)
}
def byId(id: Int): Blog = {
assert(id > 0, "i must be greater than 1")
id
}
byId(0) ⇒ AssertionError
require
with optional message is also possible
def byId(id: Int): Blog = {
require(id > 0, "i must be greater than 1")
id
}
byId(0) ⇒ IllegalArgumentException
require
's message is call by name!
There are exceptions in Scala and they are typically case classes
case class BlogNotFoundException(message: String) extends Exception(message)
def byId(id: Int): Blog = {
require(id > 0, "i must be greater than 1")
if(id == 1) {
id
} else {
throw BlogNotFoundException(s"Could not find blog with ID $id")
}
}
byId(1)
try {
byId(2)
} catch {
case BlogNotFoundException(message) => message
}
Try catch is an expression with return value
val blog = {
try {
byId(2)
} catch {
case BlogNotFoundException(message) => message
}
}
Either can be used for explicit types
val blog: Either[String, Blog] = {
try {
Right(byId(2))
} catch {
case BlogNotFoundException(message) => Left(message)
}
}
blog match {
case Right(blog) => blog
case Left(message) => 0
}
By convention is left the error and right the success!
Either right
or left to make it work like collections
blog.right.map(i => i * 10) ⇒ map will not be executed, since it is left
blog.left.map(i => i * 10) ⇒ map will be executed