Scala Try Type

Try[A] wraps a computation that might throw an exception. Instead of using try-catch everywhere, you call Try { ... } and get back either a Success(value) or a Failure(exception). This turns exception-prone code into a value that you can transform, chain, and handle functionally.

The Structure


Try[A]
  │
  ├── Success(value: A)         →  computation succeeded
  │
  └── Failure(exception: Throwable) →  computation threw an exception

Creating a Try

import scala.util.{Try, Success, Failure}

val good = Try(10 / 2)           // Success(5)
val bad  = Try(10 / 0)           // Failure(ArithmeticException: / by zero)
val parse = Try("42".toInt)      // Success(42)
val fail  = Try("abc".toInt)     // Failure(NumberFormatException: ...)

println(good)   // Success(5)
println(bad)    // Failure(java.lang.ArithmeticException: / by zero)

Pattern Matching on Try

def safeDivide(a: Int, b: Int): Try[Double] =
  Try(a.toDouble / b)

safeDivide(10, 4) match
  case Success(result) => println(f"Result: $result%.2f")
  case Failure(ex)     => println(s"Error: ${ex.getMessage}")
// Result: 2.50

safeDivide(10, 0) match
  case Success(result) => println(f"Result: $result%.2f")
  case Failure(ex)     => println(s"Error: ${ex.getMessage}")
// Error: / by zero

map and flatMap

val result = Try("123")
  .map(_.toInt)
  .map(_ * 2)
  .map(n => s"Double: $n")

println(result)   // Success(Double: 246)

val failure = Try("abc")
  .map(_.toInt)     // Failure here
  .map(_ * 2)       // skipped
  .map(n => s"$n")  // skipped

println(failure)   // Failure(NumberFormatException: ...)

recover and recoverWith

val safe = Try("not-a-number".toInt)
  .recover {
    case _: NumberFormatException => 0   // fallback value
  }

println(safe)   // Success(0)

// recoverWith returns another Try
val safe2 = Try("not-a-number".toInt)
  .recoverWith {
    case _: NumberFormatException => Try("999".toInt)
  }
println(safe2)   // Success(999)

For Comprehension with Try

def parseDouble(s: String): Try[Double]  = Try(s.toDouble)
def safeSqrt(n: Double): Try[Double] =
  if n >= 0 then Success(Math.sqrt(n))
  else Failure(new IllegalArgumentException("Negative number"))

val computation =
  for
    n    <- parseDouble("16.0")
    root <- safeSqrt(n)
  yield f"√$n%.1f = $root%.1f"

println(computation)   // Success(√16.0 = 4.0)

val bad =
  for
    n    <- parseDouble("abc")   // Failure here
    root <- safeSqrt(n)          // skipped
  yield root

println(bad)   // Failure(NumberFormatException: ...)

Converting Try to Other Types

val t1 = Try(42)
val t2 = Try(throw new RuntimeException("oops"))

t1.toOption   // Some(42)
t2.toOption   // None

t1.toEither   // Right(42)
t2.toEither   // Left(RuntimeException: oops)

t1.getOrElse(-1)   // 42
t2.getOrElse(-1)   // -1

Wrapping External Calls

import scala.io.Source

def readFile(path: String): Try[String] =
  Try(Source.fromFile(path).mkString)

def parseJson(content: String): Try[Map[String, String]] =
  Try(Map("key" -> content.take(20)))  // simplified

val result = readFile("config.json").flatMap(parseJson)

result match
  case Success(config) => println(s"Loaded config: $config")
  case Failure(ex)     => println(s"Failed to load: ${ex.getMessage}")

Try vs Either vs Option


Situation                         Use
──────────────────────────────    ─────────
Code that throws exceptions       Try
Failure with a custom message     Either
Value may simply be missing       Option

Practical: Chained Safe Operations

case class Config(host: String, port: Int, timeout: Int)

def parseConfig(raw: Map[String, String]): Try[Config] =
  for
    host    <- Try(raw("host"))
    portStr <- Try(raw("port"))
    port    <- Try(portStr.toInt)
    timeStr <- Try(raw("timeout"))
    timeout <- Try(timeStr.toInt)
  yield Config(host, port, timeout)

val good = Map("host" -> "localhost", "port" -> "5432", "timeout" -> "30")
val bad  = Map("host" -> "localhost", "port" -> "NaN",  "timeout" -> "30")

println(parseConfig(good))   // Success(Config(localhost,5432,30))
println(parseConfig(bad))    // Failure(NumberFormatException: For input string: "NaN")

Leave a Comment

Your email address will not be published. Required fields are marked *