We have a system that is possible to customise using groovy scripts and I've spotted a very strange effect on the type of exceptions throw from these scripts.
We have a groovy script with the following:
process {
throw new Exception("weeee")
}
Process is defined as a Closure in the base class of the script:
public abstract class ScriptBaseClass extends Script {
Closure process;
public void process( Closure code ) {
process = (Closure) code.clone();
}
}
In the Java class that actually runs the scripts we have the following method (omitted all the set up code as it doesn't seem relevant):
public void process() {
try {
script.process.call();
} catch (Exception e) {
logger.debug("exception thrown from groovy script", e);
throw e;
}
}
Note the process method here doesn't declare it throws any exceptions. However it quite clearly re-throws the Exception e that it caught. This code is valid, it compiles and runs quite happily. It throws the Exception as I wanted.
Does any one know how this is legal code? In theory I shouldn't be able to throw a checked exception out of a method that doesn't declare that it throws it.
A try/catch block is placed around the code that might generate an exception. All of your code which could raise an exception is placed in the Protected code block. In the catch block, you can write custom code to handle your exception so that the application can recover from the exception.
The try-catch is the simplest method of handling exceptions. Put the code you want to run in the try block, and any Java exceptions that the code throws are caught by one or more catch blocks. This method will catch any type of Java exceptions that get thrown. This is the simplest mechanism for handling exceptions.
It works because Java compiler (starting since Java 7) can determine re-thrown exception. For catch (Exception e)
it thinks it's RuntimeException
because there were no other (checked) exception declared in call()
.
You can read about it there, for example: https://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html
So this code compiles perfectly:
public void xxxxx() {
try {
System.out.println('Hi!'); //or anything else w/o declared exceptions
} catch (Exception e) {
throw e;
}
}
Java compiled sees that only RuntimeException could be caught here, so it doesn't ask you do declare anything.
But for this:
public void xxxxx() {
try {
throw new IOException(); //or anything that have declared checked exception
} catch (Exception e) {
throw e;
}
}
it will fail to compile, because IOException
could be caught and re-thrown
Introducing closures or anything Groovy related is unnecessary complexity. The following is valid Java code:
public class Demo {
public void someMethod() {
try {
System.out.println("Hello");
} catch (Exception e) {
throw e;
}
}
}
Note that the following is not valid and will not compile:
import java.sql.*;
public class Demo {
public void someMethod() {
try {
Connection c = DriverManager.getConnection("", "", "");
} catch (SQLException e) {
throw e;
}
}
}
Groovy and the JVM don't really care about an exception being a checked one or not. Only the Java compiler cares about this here. In fact you can use the catch on any RuntimeException or its parent classes (of which Exception is one) without requiring it being declared as thrown from something called in the try-block. So it is fine by the compiler to catch Exception or Throwable even. Of course, from a program logic view it is an entirely different matter.
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