Do not throw exceptions in your code, avoid using a function that throws when you can. If not possible catch
the exception an return a relevant result.
In Scala, exceptions are not documented and very hard to track (just like null
), so you can't be sure everything is correctly handled and given a big enough program, you can be sure something is NOT correctly handled.
Exceptions, like every side-effect, are breaking referential transparency which makes understanding code really hard and refactoring very fragile.
Instead of throwing exceptions, use a specific type to represent the function semantics:
Option[A]
when something can be present or notEither[E, A]
when possible errors are limitedTry[A]
when you don't know what may fail
Common throwing functions and how to replace them:
Seq[A].head
=>Seq[A].headOption
Seq[A].tail
=>Seq[A].drop(1)
Seq[A].last
=>Seq[A].lastOption
Seq[A].reduce
=>Seq[A].reduceOption
orSeq[A].fold
Option[A].get
=>Option[A].getOrElse
Try[A].get
=>Try[A].getOrElse
This rule is also present in other best practice guides: