Skip to content

Scala: scala.util.Try

The type scala.util.Try is an operation that may result in either an exception or a valid output. Let’s explore a few of its usages, including single and chained calls to scala.util.Try.

The Try operation will result in either a Success or Failure. To simplify, think about it an Either for successes and failures instead of Left and Right, but proper for encapsulating exceptions instead of other arbitrary values.

How is it different than try/catch/finally?

The main difference between Try and the try/catch/finally is that the Try operation allows you to pipeline (or pile-up, chain) operations that may result in errors, by using the map and flatMap operations and by applying pattern matching, whereas a try/catch/finally focus on a specific error.

Single scala.util.Try operation

Let’s say we wouldn’t like to try parsing a String into a java.time.Instant, but we are not sure whether this will work. We can create a function that results in a Try[Instant]:

def tryIt(value: String): Try[Instant] = Try(Instant.parse(value))

Now, we can invoke our function and use pattern matching to check whether it worked or not:

def simpleTry(): Unit = {
  tryIt("2020-11-17T00:00:00Z") match {
    case Success(instant)   => println(s"Success at $instant!")
    case Failure(exception) => println(s"Not good: $exception")
  }
}

The code above will print the successfully parsed instant to the console:

Success at 2020-11-17T00:00:00Z!

However, if we don’t provide a value that can be parsed:

def singleTryWithFailure(): Unit = {
  tryIt("not an instant") match {
    case Success(instant)   => println(s"Success at $instant!")
    case Failure(exception) => println(s"Not good: $exception")
  }
}

Then it will print the error:

Not good: java.time.format.DateTimeParseException: Text 'not an instant' could not be parsed at index 0

Chained scala.util.Try operations

Now things get a bit more interesting. Try is excellent when chained, allowing to keep trying until you get the result, or finally hit the end of the chain and get the error.

Let’s look again at our function that may generate an error:

def tryIt(value: String): Try[Instant] = Try(Instant.parse(value))

And add yet another function, just to show that you can chain different functions, as long as they have the same return type:

def tryThat(): Try[Instant] = Try(Instant.now())

Now, let’s chain three calls, where the first two will fail but the last one will succeed. We can do this by using the orElse function:

def chainedTry(): Unit = {
  tryIt("won't work") orElse tryIt("won't work either") orElse tryThat match {
    case Success(instant)   => println(s"Success at $instant!")
    case Failure(exception) => println(s"Not good: $exception")
  }
}

Which will print the current date and time:

Success at 2020-11-16T23:57:33.998Z!

But in case everything fails, you’ll get the latest exception. The following code:

def chainedTryWithFailure(): Unit = {
  tryIt("won't work") orElse tryIt("nothing will work") match {
    case Success(instant)   => println(s"Success at $instant!")
    case Failure(exception) => println(s"Not good: $exception")
  }
}

Produces this output;

Not good: java.time.format.DateTimeParseException: Text 'nothing will work' could not be parsed at index 0

Conclusion

There were just a few example of what Try is capable of. Always check the documentation and explore the functions available in the type to find other ways of using it.

The source-code of this tutorial can be found on this GitHub repository.

I hope this helps. See ya!

Tags:

Leave a Reply

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