this is a test program:
object Test {
def main(args: Array[String]): Unit = {
// there is an unhandled exception in here, I expect program can remind me, and I can handled it before running.
myException()
}
def myException: Unit ={
throw new Exception
}
}
In Java, when I called a method with unhandling exception, the program will occur error, and tell you add throws declaration or surround with try/catch.
How to know the program have unhandled exceptions before running in Scala?
Scala has a somewhat different philosophy with regards to Exceptions.
The rule of thumb is to not use them unless for something truly exceptional and, thus "let it fail". The reason invoked behind this rule is that, in FP terms, exceptions break referential transparency.
The good practice is to use Either or Option to handle/wrap "errors" rather than throwing exceptions. (the link provided by #Tawkir seems a good read)
Unfortunately this does not help when interfacing with Java code which often uses Exceptions for program control flow, and the compiler will not help you there. A practical way around this is to wrap Exception throwing code with a Try and then call recover or recoverWith to handle these exceptions and, say, wrap them in another structure.
Please note that you can mark a scala method with an #throws annotation to specify the Exception(s) that this method throws, but this should really be used when writing scala code meant to be used by a Java caller expecting an Exception to be thrown.
There's no distinction between checked and unchecked exceptions in the JVM. This is only enforced in the Java compiler, based on whether the class extends RuntimeException or not. Scala compiler doesn't check it, so, there is no way to know, does program have unhandled unchecked exceptions, or not.
Related
I'm trying to understand how to use effect monads (cats.effect.IO or scalaz.IO does not matter). Imagine I have the following method:
def extract(str: String): String = {
if(str.contains("123"))
"123"
else
throw new IllegalArgumentException("Boom!")
}
Since this method is impure (throws exception) and I need to combine its result with another effectful computation (network-IO) is it a good practice to just wrap it into IO as follows:
def extract(str: String): IO[String] = IO {
if(str.contains("123"))
"123"
else
throw new IllegalArgumentException("Boom!")
}
Is it a common use case of Effect monads?
Whether this is appropriate or not depends on what you want to express.
It's not like your first def extract(str: String): String-method definition is somehow invalid: you are just sweeping all the exceptions and side-effects under the rug, so that they aren't visible in the signature. If this is irrelevant for your current project, and if it's acceptable that a program simply crashes with a long stack trace of the thrown exception, then do it, no problem (it's easy to imagine one-off throw-away scripts where this would be appropriate).
If instead you declare def extract(str: String): IO[String] = IO { ... }, then you at least can see in the signature that the function extract can do something impure (throw an exception, in this case). Now the question becomes: who is responsible for dealing with this exception, or where do you want to deal with this exception? Consider this: if the exception is thrown, it will emerge in your code in the line where something like yourProgram.unsafeRunSync() is invoked. Does it make sense to deal with this exception there? Maybe it does, maybe it doesn't: nobody can tell you. If you just want to catch the exception at the top level in your main, log it, and exit, then it's appropriate.
However, if you want to deal with the exception immediately, you have better options. For example, if you are writing a method that prompts for a file name, then tries to extract something from this name, and finally does some IO on files, then the return type IO[String] might be too opaque. You might want to use some other monad instead (Option, Either, Try etc.) to represent the failed extraction. For example, if you use Option[String] as return type, you no longer have to deal with an obscure exception thousand miles away in your main method, but instead you can deal with it immediately, and, for example, prompt for a new file name repeatedly.
The whole exercise is somewhat similar to coming up with a strategy how to deal with exceptions in general, only here you are expressing it explicitly in the type signatures of your methods.
This is a rather general question, but hopefully a reasonable one. When is ExecutionContext#reportFailure(Throwable) called?
It doesn't seem to be called in the Scala standard library. I suppose I perhaps should call it in some circumstances? What are these?
This method reports exceptions that cannot be reported otherwise.
It is called when an exception happens during the execution of a callback that has no other way of reporting failure. In particular, calls to Future.onComplete (e.g. via Future.foreach) return Unit and may be executed on any thread, so they have no way of reporting failure back to their callers. When an exception is thrown within onComplete, it is sent to this method.
It is called a couple of times deep within the implementation for Promise in the standard library. See the source.
try onComplete(value) catch { case NonFatal(e) => executor reportFailure e }
An ExecutionContext can implement reportFailure to execute arbitrary code when a future/promise fails. The only thing in the standard library that implements this method is ExecutionContextImpl, which is not in the public API, but found here. This class accepts a reporter: Throwable => Unit function. The default ExecutionContext.Implicits.global uses ExecutionContext.defaultReporter, which simply prints the stack trace to System.err.
If you wanted to customize the behavior, you could need to define your own ExecutionContext. It's difficult to imagine a scenario where you'd want to produce some other side-effect other than logging the stack trace, or some other kind of logging.
Given a method in UserService: update, what's the best way to handle errors/exceptions here?
Option A:
def update(...): Try[User]
In this way, I need to define my custom exceptions and throw them in the function body when needed. Most of these exceptions are business errors (e.g. user_id cannot be changed, etc). The point here is no matter what exception(s) are thrown (business error, network exception, DB IO exception, etc), treat them the same way and just return a Failure(err) - let the upper layer handle them.
Option B:
def update(...): Either[Error, User]
This is the exception-free way. In the function body it catches all possible exceptions and turns them into Error, and for business errors just return Left[Error].
Using Try seems to be a more natural way to me as I want to handle errors. Either is a more generic thing - Either[Error, T] is just one special case and I think Try is invented for this special case. But I also read that we should avoid using exceptions for error handling...
So, which solution is better, and why?
There's no silver bullet.
As you noted already, Try is simply a more specialized version of Either, where the Left type is fixed to Throwable.
Try might be a good fit if you need to materialize exceptions thrown by external (perhaps java) libraries, as its constructor automatically catches them.
Another advantage of Try is that it has map and flatMap, so you can use it directly in for-comprehensions, whereas with Either you would have to explicitly project on the right case.
Anyway, there's plenty of alternative implementations with a "right-bias", and probably the scalaz \/ type is the most popular one.
That being said, I typically use \/ or the almost equivalent Validation (both from scalaz), as I like having the ability of returning errors that do not extend Throwable.
It also allows for more precise error types, which is a huge win.
If a Scala future fails, and there is no continuation that "observes" that failure (or the only continuations use map/flatMap and don't run in case of failure), then errors go undetected. I would like such errors to be at least logged, so I can find bugs.
I use the term "observed error" because in .Net Tasks there is the chance to catch "unobserved task exceptions", when the Task object is collected by the GC. Similarly, with synchronous methods, uncaught exceptions that terminate the thread can be logged.
In Scala futures, to 'observe' a failure would mean that some continuation or other code reads the Exception stored in the future value before that future is disposed. I'm aware that finalization is not deterministic or reliable, and presumably that's why it's not used to catch unhandled errors, although .Net does succeed in doing this.
Is there a way to achieve this in Scala? If not, how should I organize my code to prevent unhandled error bugs?
Today I have andThen checkResult appended to various futures. But it's hard to know when to use this and when not to: if a library method returns a Future, it shouldn't checkResult and log errors itself, because the library user may handle the failure, so the responsibility falls onto the user. As I edit code I sometimes need to add checks and sometimes to remove them, and such manual management is surely wrong.
I have concluded there is no way to generically notice unhandled errors in Scala futures.
You can just use Future.recover in the function that returns the Future.
So for instance, you could just "log" the error and rethrow the original exception, in the simplest case:
def libraryFunction(): Future[Int] = {
val f = ...
f.recover {
case NonFatal(t) =>
println("Error : " + t)
throw t
}
}
Note the use of NonFatal to match all the exception types it is sensible to catch.
That recover block could equally return an alternative result if you wish.
I was reviewing my code for the last time searching for exceptions when I stopped on this line of code:
var list: Array[String] = Source.fromFile(this.Path).getLines.toArray
I searched in the documentation on scala-lang but it seems that none of the methods of that line throws any kind of ioException...
How is that possible?
EDIT:
try {
var list: Array[String] = Source.fromFile("").getLines.toArray
}
catch {
case ex:Exception => println(ex.getMessage)
}
does not print anything, why?
Checked exceptions are enforced by the javac, the JVM don't really know about them. And contrary to Java, Scala doesn't care about checked exceptions.
Look at Source for instance, you won't notice any code dealing with exceptions. Something that is impossible in good old Java, which would require try/catchs or throws clauses.
Despite that, a Scala library author may still want to make sure that Java users check for these exceptions, so there is the #throws annotation, which let you declare that a method may throw a exception just like throws Java clause. Make sure to keep in mind that #throws is only for Java consumption.
You may also want to take look at scala.util.control.Exception. It contains all sorts of goodies for dealing with exceptions.
Source.fromFile calls java.io.FileInputStream.open, which throws a FileNotFoundException if you give it a nonexistent file.
Source.fromFile doesn't catch this, so it will be seen in your code.
I suspect many of the other exceptions possible in the java.io package are similarly unhandled, but apparently undocumented.