Exceptions & Error Handling

19.1 try/catch/finally

try is an expression. Use NonFatal to avoid catching fatal errors (OutOfMemoryError, InterruptedException, ...).

import java.io.*

def readFirstLine(path: String): String =
  val reader = BufferedReader(FileReader(path))
  try reader.readLine()
  catch
    case e: FileNotFoundException => s"missing: ${e.getMessage}"
    case e: IOException => throw RuntimeException("io failed", e)
    case scala.util.control.NonFatal(e) => s"other: $e"
  finally reader.close()

19.2 Throwing & custom exceptions

Scala has no checked exceptions (use @throws[IOException] for Java callers).

class ValidationException(msg: String) extends Exception(msg)
throw ValidationException("bad input")
require(x > 0, "x must be positive")     // IllegalArgumentException
assert(list.nonEmpty)                     // AssertionError (can be elided)
???                                       // NotImplementedError placeholder

19.3 Resource management with Using

import scala.util.Using
import scala.io.Source

val lines: Try[List[String]] = Using(Source.fromFile("data.txt"))(_.getLines().toList)

Using.resources(openA(), openB()) { (a, b) => ... }

19.4 Error-handling strategy

Model expected failures with Option / Either (or effect types).

Wrap throwing APIs at the boundary with Try / Either.catchNonFatal.

Accumulate errors with cats.data.Validated / ValidatedNel.

Let truly unexpected errors propagate to a top-level handler.