In order to illustrate how exceptions bubble up the call stack, we are going to create a new averageAge function, which calculates the average age of a list ofPerson instances, using their string descriptions, as shown in the following code:
def averageAge(descriptions: Vector[String]): Double = { val total = descriptions.map(createPerson).map(_.age).sum total / descriptions.length }
This function calls our previously implemented createPerson function, and therefore will throw any exception that is thrown bycreatePersonbecause there is notry...catchblock inaverageAge.
Now, we can implement another function on top that will parse an input containing several Person descriptions and return a summary in a string. It will print an error message in case the input cannot be parsed, as shown in the following code:
import scala.util.control.NonFatal def personsSummary(personsInput: String): String = { val descriptions = personsInput.split("\n").toVector val avg = try { averageAge(descriptions) } catch { case e:AgeNegativeException => println(s"one of the persons has a negative age: $e") 0 case NonFatal(e) => println(s"something was wrong in the input: $e") 0 } s"${descriptions.length} persons with an average age of $avg" }
In this function, we declare an avg value, which will get the return value ofaverageAgeif no exception is thrown. If one of the descriptions contains a negative age, our catch block will print an error message, andavgwill be assigned the value of 0. If another type of exception is thrown, and this exception isNonFatal, then we print another message andavgwill also be assigned the value of 0. A fatal exception is an exception that cannot be recovered, such asOutOfMemoryException. You can look at the implementation ofscala.util.control.NonFatalfor more details.
The following code shows a few sample calls to personsSummary:
scala> personsSummary( """John 25 |Sharleen 45""".stripMargin) res1: String = 2 persons with an average age of 35.0
scala> personsSummary( """John 25 |Sharleen45""".stripMargin) something was wrong in the input: java.lang.ArrayIndexOutOfBoundsException: 1 res2: String = 2 persons with an average age of 0.0
scala> personsSummary( """John -25 |Sharleen 45""".stripMargin) one of the persons has a negative age: $line5.$read$$iw$$iw$AgeNegativeException: age should be > 0 res3: String = 2 persons with an average age of 0.0
As we can see, as soon as any of the descriptions cannot be parsed, an error is printed and the average age is set to 0.