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 { .. }
?
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.
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.
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.
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.
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 Error
s).
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With