Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a value from try-catch

Tags:

scala

Here is a method in Scala:

def method1(arg: String*): List[String] = {
        try {
          new MyClass(new URL(arg(0)))
            .map(x => x.getRawString.toString)
        }
        catch {
          case e: Exception => e.printStackTrace()
        }
}

It complains on

found   : Unit
[error]  required: List[String]

If I added an additional value so that:

def method1(arg: String*): List[String] = {
        val result = try {
          new MyClass(new URL(arg(0)))
            .map(x => x.getRawString.toString)
        }
        catch {
          case e: Exception => e.printStackTrace()
        }

       result
}

it would say

found   : Any
[error]  required: List[String]

which is odd -- isn't this the same as the first approach?

Anyway, what is the Scala's standard way of dealing with this kind of situations -- returning a value from try { .. } catch { .. } ?

like image 311
Alan Coromano Avatar asked Jul 06 '13 07:07

Alan Coromano


People also ask

Can we return in try catch block?

Yes, we can write a return statement of the method in catch and finally block. There is a situation where a method will have a return type and we can return some value at any part of the method based on the conditions.

How do I return an item on try catch block?

Return your Dictionary end of your try block, return null from your catch . And every time you call this function check for returning value. If it's null then that means something bad happened. Because returning a null Dictionary is the same as returning null directly.

Can you return in a try statement?

you can use a return statement inside the try block, but you have to place another return outside the try block as well. If you pass true while calling sayHello method, it would return from try block. A return statement has to be at the method level instead of at any other specific level.

How do you return a value from a catch block in Java?

Whenever try-block executes successfully, then it can always return value for this method. But if any exception is raised & it is handled in the corresponding catch-block –> return statement at the end of method will be executed and returns the value for this method after executing finally-block.


3 Answers

The problem is that in the case of an exception, there is no value to return. So you have to decide what value to return in such a case. It can be an empty list (if you really don't care about handling the error - not recommended!):

def method1(arg: String*): List[String] =
  try {
    new MyClass(new URL(arg(0)))
        .map(x => x.getRawString.toString)
  } catch {
    case e: Exception => { e.printStackTrace(); Nil; }
  }

A standard Scala way would be to return an Option, which makes it clear to the caller what happened:

def method1(arg: String*): Option[List[String]] =
  try {
    Some(new MyClass(new URL(arg(0)))
        .map(x => x.getRawString.toString))
  } catch {
    case e: Exception => { e.printStackTrace(); None; }
  }

or perhaps return the exception itself:

def method1(arg: String*): Either[Exception,List[String]] =
  try {
    Right(new MyClass(new URL(arg(0)))
        .map(x => x.getRawString.toString))
  } catch {
    case e: Exception => Left(e)
  }

Since this pattern is relativelly common, there is a special Scala class Try just for this purpose, that gives these concepts meaningful names and adds many helpful methods. Try[A] encapsulates the result of a computation that returns A, or an exception if the computation failed:

 sealed abstract class Try[+T]
 final case class Success[+T](value: T) extends Try[T]
 final case class Failure[+T](exception: Throwable) extends Try[T]

so a literal rewrite of your method would be

def method1(arg: String*): Try[List[String]] =
  try {
    Success(new MyClass(new URL(arg(0)))
        .map(x => x.getRawString.toString))
  } catch {
    case e: Exception => Failure(e)
  }

But of course Scala has methods for this pattern (after all that's what Try is for), so you can write just

def method1(arg: String*): Try[List[String]] =
  Try { new MyClass(new URL(arg(0)))
        .map(x => x.getRawString.toString)) }

(There is a slight difference, Try { ... } also catches some Errors).

like image 199
Petr Avatar answered Oct 11 '22 17:10

Petr


It complains because not all branches return the result:

def method1(arg: String*): List[String] = {
        try {
          new MyClass(new URL(arg(0)))
            .map(x => x.getRawString.toString) // ok, here I know what to do
        }
        catch {
          case e: Exception => e.printStackTrace() // ???? What to return here??? 
                                                   // ok, will return Unit
        }
}

The common type of Something and Unit is Any. So what you need to do in both cases (with, or without result variable) is to return value in both branches (possibly some dummy value, like empty List in catch case).

EDIT

The errors are different because without val compiler can track that flow down to the branch and notice that function return type and catch result are different. With val there was no type constraints on val so it can happily infer that val result has Any type and then, when you return result it confronts with function result type. If you specify result type explicitly as val result: List[String] = ... error message will be the same.

like image 6
om-nom-nom Avatar answered Oct 11 '22 18:10

om-nom-nom


In Scala such things should be better done with monadic style:

def fun(arg: Strign*): Option[List[String]] = Try {
    new MyClass(new URL(arg(0))).map(_.getRawString.toString)
}.toOption

Update

If you look at the implementation of Try's apply you'll see and interesting code:

/** Constructs a `Try` using the by-name parameter.  This
 * method will ensure any non-fatal exception is caught and a
 * `Failure` object is returned.
 */
def apply[T](r: => T): Try[T] =
  try Success(r) catch {
    case NonFatal(e) => Failure(e)
  }

so Try is just a wrapper for try/catch for monadic chaining

like image 5
4lex1v Avatar answered Oct 11 '22 18:10

4lex1v