Re: Catching mulitple Exceptions in JDK 1.7
On 8/2/2011 6:56 AM, Roedy Green wrote:
On Mon, 1 Aug 2011 23:54:34 -0700 (PDT), Lew<lewbloch@gmail.com>
wrote, quoted or indirectly quoted someone who said :
In fact, if you only want to handle the IOException-ness of the exception, =
you wouldn't even bother mentioning 'SQLException' at all. You'd just 'cat=
ch(IOException...)'.
Here is a better example to illustrate my question:
catch (IllegalArgumentException|IOException ex)
What is the compile-time type of ex?
What is the run-time type of ex if you got an
IllegalArgumentException?
"run-time type of ex" is presumably shorthand for "class of the object
referenced by ex". Since ex references the object that was thrown from
the try block, the class of the object referenced by ex would be
IllegalArgumentException.
What is the run-time type of ex if you got an IOException ?
There may be more grown-up terms for "compile time type" and "run time
type", but I think you know what I mean.
Or is there a rule that catch (a | b ex ) requires a to be a subclass
of b, which would neatly sidestep the problem, but then the feature
would not do anything useful.
I've done an experiment, with interesting results.
Before I go into more detail, I must protest against having to
experiment. One of the things I've really liked about Java has been the
quality of the documentation. I can generally predict what will happen
when a short program is compiled, and, if compilable, run just by
reading the JLS, the API documentation, and advance documentation of new
features.
Test program:
public class TestExceptions {
private static Object dummy;
public static void main(String[] args){
for(int key = 0; key <=2; key++){
try {
System.out.println("key="+key);
thrower(key);
System.out.println("No exception");
} catch (IllegalArgumentException | NullPointerException e) {
System.out.println("Caught "+e);
// IllegalArgumentException e1 = e;
// NullPointerException e2 = e;
RuntimeException e3 = e;
} catch (Dummy1 | Dummy2 e){
e.someMethod();
e.getCause();
// IllegalArgumentException e4 = e;
}
}
}
private static void thrower(int key) throws Dummy1, Dummy2 {
switch (key) {
case 0: System.out.println(dummy.hashCode());
case 1: return;
default: throw new IllegalArgumentException();
}
}
interface DummyInterface {
void someMethod();
}
private static class Dummy1 extends Throwable implements DummyInterface {
public void someMethod(){
}
}
private static class Dummy2 extends Throwable implements DummyInterface {
public void someMethod(){
}
}
}
Results:
Program as quoted compiles and runs with the following output.
key=0
Caught java.lang.NullPointerException
key=1
No exception
key=2
Caught java.lang.IllegalArgumentException
Uncommenting the first comment line gets a compile time error:
TestExceptions.java:11: error: incompatible types
IllegalArgumentException e1 = e;
^
required: IllegalArgumentException
found: RuntimeException
Uncommenting the second comment line gets a similar error.
Uncommenting the third comment line gets a compile time error:
TestExceptions.java:17: error: incompatible types
IllegalArgumentException e4 = e;
^
required: IllegalArgumentException
found: INT#1
where INT#1 is an intersection type:
INT#1 extends Throwable,DummyInterface
Interpretation:
The compile time type of the first catch reference is RuntimeException,
the most specific class that is a superclass of both
IllegalArgumentException and NullPointerException. This makes sense. It
allows direct use of common superclass methods - for example, a catch
block for two of the SQLException subclasses could use the getSQLState()
method without any casting.
The second catch block, which is not actually executed, is interesting.
The caught classes are both direct subclasses of Throwable, but also
implement a common interface. The compiler allows calls to both
Throwable and DummyInterface methods, using a "intersection type".
It seems to generally do the most useful thing it could, but I really
would like documentation that would let me predict the results without
running the experiments.
Patricia