What is the correct way to return from an exception in Scala?

In a non-functional language, I can do something like:

try { // some stuff } catch Exception ex { return false; } // Do more stuff return true; 

In Scala, however, this scheme is clearly incorrect. If my scala code looks like this:

 try { // do some stuff } catch { case e: Exception => // I want to get out of here and return false ) } // do more stuff true 

How to do it right? Of course, I do not want to use the "return" operator, but I also do not want to skip and "do more things" and ultimately return true.

+7
scala
source share
5 answers

You want to imagine a calculation that can either succeed or signal an error. This is an ideal use case for the monad Try .

 import scala.util.{ Try, Success, Failure } def myMethod: Try[Something] = Try { // do stuff // do more stuff // if any exception occurs here, it gets wrapped into a Failure(e) } 

So, you return Try instead of Bool , which is infinitely more clear and idiomatic.

Usage example:

 myMethod match { case Success(x) => println(s"computation succeded with result $x") case Failure(e) => println(s"computation failed with exception $e.getMessage") } 

If you don't even care about the exception, but just want to return the value if successful, you can even convert Try to Option .

 def myMethod: Option[Something] = Try { // do stuff // do more stuff // return something // if any exception occurs here, it gets wrapped into a Failure(e) }.toOption myMethod match { case Some(x) => println(s"computation succeded with result $x") case None => println("computation failed") } 

To answer the question in the comments, you can do

 Try { // do stuff } match { case Failure(_) => false case Success(_) => // do more stuff // true } 

although I would suggest returning something more meaningful than Boolean when that makes sense.

Of course it can be nested.

 Try { // do stuff } match { case Failure(_) => false case Success(_) => // do more stuff Try { // something that can throw } match { case Failure(_) => false case Success(_) => // do more stuff true } } 

but you should consider adding Try fragments to individual functions ( Try returning).

Ultimately, we can take advantage of the fact that Try is a monad and does something like this.

 Try { /* java code */ }.flatMap { _ => // do more stuff Try { /* java code */ }.flatMap { _ => // do more stuff Try { /* java code */ } } } match { case Failure(_) => false // in case any of the Try blocks has thrown an Exception case Success(_) => true // everything went smooth } 
+11
source share
 scala> def f() = try { ??? ; 1 } catch { case _: Throwable => 2 } f: ()Int scala> f() res2: Int = 2 scala> import util._ import util._ scala> def g() = Try { ??? ; 1 } recover { case _ => 2 } get warning: there was one feature warning; re-run with -feature for details g: ()Int scala> g() res3: Int = 2 

NTN. Small functions help.

Another hint:

 scala> def j() = Try (1) map (_ + 42) recover { case _ => 2 } get warning: there was one feature warning; re-run with -feature for details j: ()Int scala> j() res4: Int = 43 
+3
source share

try-catch expression is not suitable for functional programming.

Anyway, a simple solution that still uses try-catch :

 val result = try { // do some stuff Some(/* The final expression */) } catch { case e: Exception => // Do something or nothing None } result match { case Some(r) => // Do something with r true case None => false } 

You can use scala.util.Try for cleaner and more functional code.
See https://codereview.stackexchange.com/questions/38689/code-with-many-early-returns-exits-into-the-functional-style

I had a similar problem like you, but the answer in the Stackexchange CodeReview code really helped me.

+1
source share

'util.Try {follow some steps} .isSuccess'

0
source share

Successful or error cases can be represented by several types of Scala.

If you consider an error in the meaning of โ€œsomething is missingโ€ (for example, the file was not found), you can use Option[T] (for example, Option[File] ), with the values โ€‹โ€‹case None or Some(T) . The functions orElse , getOrElse or fold and map / flatMap can be used to send cased ones.

You can also use Either[E, T] , using (by convention), in Left(E) an error value (for example, String as an error message) and Right(T) successful T value.

Mono Try[T] or Future[T] can be used the same way.

In the I / O field, the very nice scala -arm lib provides a type of ManagedResource[T] that completes a successful ( T ) or erroneous ( List[Throwable]] ) resource-based calculation result.

In such cases, oscillation types in Scalaz are also useful.

0
source share

All Articles