I would like to update the Failure exception of a Try to provide a more understandable failure.
I successfully do this by using the following implementation:
case class NoDataAvailableException() extends Exception
[...]
Try(...) match {
case Success(f) => Success(f)
case Failure(_) => Failure(NoDataAvailableException())
}
But I think this implementation is not really elegant, so my question is:
Is there a way to do this more elegantly ?
You could use recoverWith with accepts a PartialFunction[Throwable, Try[U]]. This would allow you to map specific exceptions to successes or failures, as you wish.
case class MyException() extends Exception
Try(1 / 0) recoverWith {
case _: ArithmeticException => Failure(new MyException())
// other exceptions ...
}
You could also use an implicit class to add method of your own to Try that lets you specifically map exceptions.
implicit class TryExtension[A](t: Try[A]) {
def mapFailure(pf: PartialFunction[Throwable, Throwable]): Try[A] =
t.recoverWith(pf.andThen(Failure.apply))
}
scala> Try(1 / 0).mapFailure { case _ => new MyException }
res3: scala.util.Try[Int] = Failure(MyException)
You are looking for Try.recoverWith
Try(...) recoverWith {
case _ => Failure(NoDataAvailableException())
}
How about using try.recover or try.recoverWith?
Related
Im writing my own class Success or Error. I want to create a way to build SuccessOrError from Try and then use Try instead of ugly try-catch in flatMap. But I'm stuck at this point. How should I best write a function fromTry in order to be able to write like this?
case SuccessOrError.Success(v) ⇒ SuccessOrError.fromTry(Try(f(v)))
enum SuccessOrError[+V]:
case Success(x: V) extends SuccessOrError[V]
case Error(e : Throwable) extends SuccessOrError[V]
def flatMap[Q](f: V ⇒ SuccessOrError[Q]): SuccessOrError[Q] =
this match
case SuccessOrError.Success(v) ⇒ try f(v) catch case NonFatal(e) => SuccessOrError.Error(e)
case SuccessOrError.Error(e) ⇒ SuccessOrError.Error(e)
object SuccessOrError:
def fromTry[Q](f: Try[Q]): SuccessOrError[Q] = ???
Converting from Try to another error model is quite a common practice. Perhaps consider how they approach it in scala-cats library as inspiration
Validated
/**
* Converts a `Try[A]` to a `Validated[Throwable, A]`.
*/
def fromTry[A](t: Try[A]): Validated[Throwable, A] =
t match {
case Failure(e) => invalid(e)
case Success(v) => valid(v)
}
or Either
/**
* Converts a `Try[A]` to a `Either[Throwable, A]`.
*/
def fromTry[A](t: Try[A]): Either[Throwable, A] =
t match {
case Failure(e) => left(e)
case Success(v) => right(v)
}
or ApplicativeError
/**
* If the error type is Throwable, we can convert from a scala.util.Try
*/
def fromTry[A](t: Try[A])(implicit ev: Throwable <:< E): F[A] =
t match {
case Success(a) => pure(a)
case Failure(e) => raiseError(e)
}
Note the pattern (bad pun, applogies) of simply pattern matching on happy and unhappy cases, so we can try emulating it
def fromTry[Q](f: Try[Q]): SuccessOrError[Q] =
f match {
case scala.util.Failure(e) => SuccessOrError.Error(e)
case scala.util.Success(v) => SuccessOrError.Success(v)
}
The below is just an example to represent my case of usage,
Suppose there is a function,
def getSomeValue(request:Int):Unit = {
val retry = try {
doSomething
true
}
catch {
case _:NullPointerException => false
case _:IndexOutOfBoundsException => false
case _:Exception => true
}
if(retry)
getSomeValue(request)
}
I want to handle all the exceptions in a separate function. Like below,
def handleException = {
case _:NullPointerException => false
case _:IndexOutOfBoundsException => false
case _:Exception => true
}
And tried using it in the function as,
def getSomeValue(request:Int):Unit = {
val retry = try {
doSomething
true
}
catch handleException
if(retry)
getSomeValue(request)
}
The compiler thrown couple of errors,
Method apply is not a member of type Any
Method isDefinedAt is not a member of type Any
Could some one please let me know what I am doing wrong?
There is function recoverWith in scala.util.Try for such cases. It takes partial function which handle specified exceptions. If your Try will fall you can specify retry inside this function.
For example:
import scala.util.{Failure, Try}
def getSomeValue[A](doSomething: => A): Try[A] =
Try(doSomething).recoverWith {
case t: NullPointerException => Failure(t)
case t: IndexOutOfBoundsException => Failure(t)
case _: Exception => Try(doSomething) // retry doSomething
}
this function returns Try[A] after retry and you can handle errors on the upper-lever.
Thanks to #Luis Miguel Mejía Suárez for helping me on this,
I am able to achieve this by how he said,
def getSomeValue(request:Int):Unit = {
val result = Try(doSomething)
val retry = result match {
case Success(_) => false
case Failure(exception) => handleException(exception)
}
if(retry)
getSomeValue(request)
}
def handleException(exception: Throwable) = exception match {
case _:NullPointerException => false
case _:IndexOutOfBoundsException => false
case _:Exception => true
}
Any other answers also welcomed.
I am using Akka and would like to run some code for all cases of a PartialFunction. For actor supervision, I have something like:
val supervisorStrategy = OneForOneStrategy() {
case npe: NullPointerException => Stop
case re: RuntimeException => Restart
}
The only way I have found to run some code for all cases without having to write it again at every case, is:
val pf = new PartialFunction[Throwable, Directive] {
def apply(throwable: Throwable) = {
doSomething(throwable)
throwable match {
case NullPointerException => Stop
case RuntimeException => Restart
}
}
def isDefinedAt(throwable: Throwable) = true
}
val supervisorStrategy = OneForOneStrategy()(pf)
I have looked around and to other answers (like this one) but couldn't figure out any alternative way to the one I came up with.
Doesn't seem Akka-specific. You can always combine any two functions using andThen. Specifically:
package com.example
import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy.{Decider, Restart, Stop}
object Answer extends App {
val doSomething:PartialFunction[Throwable, Throwable] = { case e =>
println(s"doing something with $e")
e
}
val decide:Decider = {
case _:NullPointerException => Stop
case _:RuntimeException => Restart
}
val strategy = OneForOneStrategy()(doSomething andThen decide)
val errors = Seq(new NullPointerException, new RuntimeException)
errors map strategy.decider foreach println
}
More generally:
package com.example
object Answer extends App {
val inspect:PartialFunction[Throwable, Throwable] = { case e =>
println(s"inspecting $e")
e
}
val decide:PartialFunction[Throwable, String] = {
case npe:NullPointerException => "NPE!"
case iae:IllegalArgumentException => "Bad arg!"
}
val combined = inspect andThen decide
val errors = Seq(new NullPointerException, new IllegalArgumentException)
errors map combined foreach println
}
This should do it :
val supervisorStrategy = OneForOneStrategy() {
case x =>
doSomething(x)
x match {
case npe: NullPointerException => Stop
case re: RuntimeException => Restart
}
}
Thanks for the other answers, but in this Akka specific situation I can't get them to work. For instance, this won't compile:
val ft = OneForOneStrategy() { x: Throwable =>
doSomething(x)
x match {
case npe: NullPointerException => Stop
case re: RuntimeException => Stop
}
}
Error:(48, 47) type mismatch;
found : Throwable => akka.actor.SupervisorStrategy.Directive
required: akka.actor.SupervisorStrategy.Decider (which expands to) PartialFunction[Throwable,akka.actor.SupervisorStrategy.Directive]
I am using Akka 2.4.11 and Scala 2.11.8
The only working solution for me was the way I described in the initial question.
Here is an example receive part of an actor I'm working on:
def receive = {
case "begin" =>
val listOfFutures: IndexedSeq[Future[Any]] = workers.map(worker => worker ? Work("test"))
val future: Future[IndexedSeq[Any]] = Future.sequence(listOfFutures)
future onComplete {
case Success(result) => println("Eventual result: "+result)
case Failure(ex) => println("Failure: "+ex.getMessage)
}
case msg => println("A message received: "+msg)
}
When ask fails for one of the workers (in case of a timeout), sequence future completes with failure. However I want to know which worker(s) have failed. Is there a more elegant way rather than simply mapping listOfFutures one by one without using Future.sequence ?
You can use the future's recover method to map or wrap the underlying exception:
import scala.concurrent.{Future, ExecutionContext}
case class WorkerFailed(name: String, cause: Throwable)
extends Exception(s"$name - ${cause.getMessage}", cause)
def mark[A](name: String, f: Future[A]): Future[A] = f.recover {
case ex => throw WorkerFailed(name, ex)
}
import ExecutionContext.Implicits.global
val f = (0 to 10).map(i => mark(s"i = $i", Future { i / i }))
val g = Future.sequence(f)
g.value // WorkerFailed: i = 0 - / by zero
Thanks to #O__ I have come with another solution that may a better fit some some cases.
case class WorkerDone(name: String)
case class WorkerFailed(name: String)
import ExecutionContext.Implicits.global
val f = (0 to 10).map {
i => Future {i/i; WorkerDone(s"worker$i")}.recover{
case ex => WorkerFailed(s"worker$i")
}
}
val futureSeq = Future.sequence(f)
futureSeq onComplete {
case Success(list) => list.collect {case result:WorkerFailed => result}.foreach {failed => println("Failed: "+failed.name)}
case Failure(ex) => println("Exception: "+ex.getMessage)
}
// just to make sure program doesn't end before onComplete is called.
Thread.sleep(2000L)
I'm not sure that if my example is a good practice, but my aim is to know which workers did fail no matter how did they fail.
I want to flatten a Try[Option[T]] into a Try[T]
Here is my code
def flattenTry[T](t: Try[Option[T]]) : Try[T] = {
t match {
case f : Failure[T] => f.asInstanceOf[Failure[T]]
case Success(e) =>
e match {
case None => Failure[T](new Exception("Parsing error"))
case Some(s) => Success(s)
}
}
}
Is there a better way ?
You could try something like this which is a little neater:
val t = Try(Some(1))
val tt = t.flatMap{
case Some(i) => Success(i)
case None => Failure(new Exception("parsing error"))
}
More generically, this would be:
def flattenTry[T](t: Try[Option[T]]) : Try[T] = {
t.flatMap{
case Some(s) => Success(s)
case None => Failure(new Exception("parsing error"))
}
}
The trick is to convert the Option into Try for using flatmap.
Using getOrElse, you could also write:
def flattenTry[T](t: Try[Option[T]]): Try[T] = {
t flatMap { o => o map (Success(_)) getOrElse Failure(new Exception("parsing error")) }
}
You could make this even shorter, but possibly at the cost of functional purity (throwing is a side-effect) and performance (due to throwing/catching):
def flattenTry[T](t: Try[Option[T]]): Try[T] = {
Try(t.get getOrElse { throw new Exception("parsing error") })
}
One possible way is to use Try(o.get) to convert o: Option to o: Try.
This is very concise, but throws and catches exception when handling None, which might perhaps be a performance concern sometimes (or sometimes an ideological / code rules concern). Still, the code is so concise and well readable I think it is worth mentioning:
def flattenTry[T](t: Try[Option[T]]) : Try[T] = {
t.flatMap(o => Try(o.get))
}
Note: not that I recommend using it, but for completeness: even a shorter version is possible, which throws / catches even when Try is a failure:
def flattenTry[T](t: Try[Option[T]]) : Try[T] = {
Try(t.get.get)
}