{{announcement.body}}
{{announcement.title}}

Use of Either in Scala

DZone 's Guide to

Use of Either in Scala

In this article, we are going to see the use of Either in Scala. We use options in Scala but why do we want to go for Either? Either is a better approach.

· Open Source Zone ·
Free Resource

In this article, we are going to see the use of Either in scala. We use Options in scala but why do we want to go for Either?

Either is a better approach in the respect that if something fails we can track down the reason, which in Option None case is not possible.

We simply pass None but what is the reason we got None instead of Some. We will see how to tackle this scenario using Either.

Scala
 




xxxxxxxxxx
1


 
1
Either[Left, Right]


None is similar to Left which signifies Failure and Some is similar to Right which signifies Success.

Let's see with help of an example:

Scala
 




x


 
1
 def returnEither(value: String): Either[NumberFormatException, Int] =
2
  {
3
    try {
4
      Right(value.toInt)
5
    } catch {
6
      case ex: NumberFormatException => Left(ex)
7
    }
8
  }
9
returnEither("abc").map(x => println(x))


It will not print anything, Either is right biased and returnEither("abc") gives Left(java.lang.NumberFormatException: For input string: "abc")

Now let's call it on Right value.

Scala
 




xxxxxxxxxx
1


 
1
returnEither("1").map(x => println(x))


It will print 1. Yes, it is right biased as the map works on Either.right. What if i want to call map on left?

Scala
 




xxxxxxxxxx
1


 
1
returnEither("abc").left.map(x => println(x))


It will print java.lang.NumberFormatException: For input string: "abc".

Using Match case with Either

Scala
 




xxxxxxxxxx
1


 
1
 returnEither("1") match
2
  {
3
    case Right(value) => println(s"Right value: $value")
4
    case Left(ex: NumberFormatException) => println(ex)
5
  }


It will print Right value: 1

Extract value from Either

Let's say we want to extract left value from Either.

Scala
 




xxxxxxxxxx
1


 
1
  println(returnEither("abc").left)


will print LeftProjection(Left(java.lang.NumberFormatException: For input string: "abc"))

Scala
 




xxxxxxxxxx
1


 
1
  println(returnEither("1").left)


will print LeftProjection(Right(1))

Scala
 




xxxxxxxxxx
1


 
1
println(returnEither("abc").left.get)


will print java.lang.NumberFormatException: For input string: "abc".

Scala
 




xxxxxxxxxx
1


 
1
println(returnEither("1").left.get)


will print: Exception in thread "main" java.util.NoSuchElementException: Either.left.get on Right

Oops. It had the right value.

We can use getOrElse or fold for default value.

getOrElse

Scala
 




xxxxxxxxxx
1


 
1
println(returnEither("1").left.getOrElse(2)) // will print 2


fold

Scala
 




xxxxxxxxxx
1


 
1
  println(returnEither("1").fold(
2
    i => s"Found an exception: '$i'",
3
    b => s"Found int: '$b'"
4
  ))


will print Found int: '1'

Scala
 




xxxxxxxxxx
1


 
1
  println(returnEither("abc").fold(
2
    i => s"Found an exception: '$i'",
3
    b => s"Found int: '$b'"
4
  ))


will print Found an exception: 'java.lang.NumberFormatException: For input string: "abc"'

Check value is Left or Right

Scala
 




xxxxxxxxxx
1


 
1
  println(returnEither("abc").isLeft) //print true
2
  println(returnEither("1").isRight) // print true


Working with Lists using Either

Scala
 




xxxxxxxxxx
1
14
9


 
1
val list: List[Either[Int, String]] = List(Right("r1"), Left(0), Right("r2"), Left(10), Right("r3"), Left(100), Right("r4"))
2
val newList = list.map(_.map(_.toUpperCase)).map(y => y.left.map(_ * 20))
3
println(newList)


Will give List(Right(R1), Left(0), Right(R2), Left(200), Right(R3), Left(2000), Right(R4)).

Let's understand how. As we know Either is right bias so list.map(x => x.map(_.toUpperCase)), x will only have Right Values which will be converted to uppercase then as we have return type as List[Either[Int, String]] for list.map(_.map(_.toUpperCase)). y will have left and right values. All the left values will be multiplied by 20.

toRight

y.toRight(x) checks if value is empty it return Left(x) else Right(y).

Scala
 




xxxxxxxxxx
1


 
1
val ok: Either[Error, String] = Some("Yeah!").toRight(new Error("Error!"))
2
val error: Either[Error, String] = None.toRight(new Error("Error!"))
3
println(ok) // Right(Yeah!)
4
println(error) // Left(java.lang.Error: Error!)


toLeft

y.toLeft(x) checks if value is empty it return Right(x) else Left(y).

Scala
 




xxxxxxxxxx
1


 
1
val okLeft: Either[Error, String] = Some(new Error("Error!")).toLeft("Yeah!")
2
val errorLeft: Either[Error, String] = None.toLeft("Yeah!")
3
println(okLeft) // Left(java.lang.Error: Error!)
4
println(errorLeft) // Right(Yeah!)


There could be a situation where one function is called then another and then another is a chain and the exceptions are thrown freely. How do we track which function actually caused the exception?

Scala
 




x


1
val array: Array[Int] = Array(0,2)
2
def fetchElement(el: Int): Either[Exception, Int] =
3
 if (el < array.length ) Right(array(el))
4
 else Left(new ArrayIndexOutOfBoundsException("from function fetchElement"))
5
 
          
6
def reciprocal(i: Int): Either[Exception, Double] =
7
 if (i == 0) Left(new IllegalArgumentException("from function reciprocal"))
8
 else Right(1.0 / i)
9
 
          
10
def stringify(d: Double): String = d.toString
11
 
          
12
def callFunctions(s: String): Either[Exception, String] = fetchElement(s.toInt).flatMap(reciprocal).map(stringify)
13
 
          
14
callFunctions("3") match {
15
  case Left(_: ArrayIndexOutOfBoundsException) => println("Exception in fetchElement")
16
  case Left(_: IllegalArgumentException) => println("Exception in reciprocal")
17
  case Left(_) => println("got unknown exception")
18
  case Right(s) => println(s"Got reciprocal: $s")
19
}


will print Exception in fetchElement.

If call callFunctions("0") will print Exception in reciprocal

Thanks for reading!

Topics:
either, exception handling, scala

Published at DZone with permission of Jyoti Sachdeva . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}