Either & Try
In this lesson, you will learn how to handle errors safely and clearly in Scala using Either and Try. These constructs are widely used in functional programming to avoid unexpected crashes and to make error handling explicit.
Instead of throwing exceptions or returning null values, Scala encourages using types that clearly describe success and failure.
Why Error Handling Matters
Traditional error handling using exceptions can lead to:
- Hidden control flow
- Unexpected runtime crashes
- Difficult debugging
Scala’s Either and Try solve these problems by making
errors part of the program’s type system.
Understanding Either
Either[A, B] represents a value that can be one of two possibilities:
Left[A]– usually represents an errorRight[B]– usually represents a success
By convention, Right is used for successful results.
def divide(a: Int, b: Int): Either[String, Int] =
if (b == 0) Left("Division by zero")
else Right(a / b)
Using Either Safely
You can safely transform a successful value using map.
val result = divide(10, 2).map(_ * 2)
println(result)
If the value is Left, the transformation is skipped.
Chaining Operations with flatMap
When a function itself returns an Either, use flatMap
to avoid nested results.
def reciprocal(x: Int): Either[String, Double] =
if (x == 0) Left("Cannot take reciprocal of zero")
else Right(1.0 / x)
val result =
divide(20, 2).flatMap(reciprocal)
println(result)
For-Comprehensions with Either
For-comprehensions make chained error handling easy to read.
val result = for {
a <- divide(20, 2)
b <- reciprocal(a)
} yield b
println(result)
If any step fails, the entire computation returns a Left.
Understanding Try
Try is used to capture exceptions that may occur during execution.
Success(value)– represents successful computationFailure(exception)– represents an exception
import scala.util.Try
val result = Try(10 / 2)
println(result)
Transforming Try with map
Just like Either, Try supports map and flatMap.
val transformed = Try(10 / 2).map(_ * 3)
println(transformed)
If an exception occurs, the result becomes a Failure.
Recovering from Errors
You can recover from failures using recover or recoverWith.
val safeResult = Try(10 / 0).recover {
case _: ArithmeticException => 0
}
println(safeResult)
Either vs Try
Both are useful, but they serve different purposes:
- Either – best for predictable, domain-level errors
- Try – best for catching unexpected exceptions
In production systems, Either is often preferred for business logic, while Try is used near risky operations.
📝 Practice Exercises
Exercise 1
Write a function that returns an Either when dividing two numbers.
Exercise 2
Use a for-comprehension to chain two Either operations.
Exercise 3
Wrap a risky operation using Try and recover from failure.
✅ Practice Answers
Answer 1
def safeDivide(a: Int, b: Int): Either[String, Int] =
if (b == 0) Left("Cannot divide by zero")
else Right(a / b)
Answer 2
val result = for {
x <- safeDivide(20, 2)
y <- safeDivide(x, 2)
} yield y
Answer 3
val result = Try("abc".toInt).recover {
case _: NumberFormatException => 0
}
What’s Next?
In the next lesson, you will learn about For-Comprehensions and how they simplify complex transformations across collections, Option, Either, and Try.