e is of type Exception but prints Exception1 in below code:
class Exception1 extends IOException {void info(){}}
class Exception2 extends Exception {}
class TestMultiCatch {
public static void main(String args[]) {
try {
int a = 10;
if (a <= 10)
throw new Exception1();
else
throw new Exception2();
} catch (Exception1 | Exception2 e) {
e.info(); //line 1 error "The method info() is undefined for type Exception"
System.out.println(e); //prints Exception1 (after commenting line 1)
}
}
}
From what I studied "e" should be of type Exception which is common base class of Exception1 and Exception2. Which it is, as evident from message in line 1.
But then why:
System.out.println(e); //prints Exception1 and not Exception
System.out.println(e instanceof IOException); //prints true and not false
System.out.println(e instanceof Exception1); //prints true and not false
System.out.println(e instanceof Exception2); //false
? Thanks.
When you use a multi-catch clause (the Exception1 | Exception2 e
form of catch
), the compile-time type of e
is the greatest type that the two types have in common, since of course the code has to handle either type of exception.From the spec:
An exception parameter may denote its type as either a single class type or a union of two or more class types (called alternatives). The alternatives of a union are syntactically separated by
|
.A catch clause whose exception parameter is denoted as a single class type is called a uni-catch clause.
A catch clause whose exception parameter is denoted as a union of types is called a multi-catch clause.
...
The declared type of an exception parameter that denotes its type as a union with alternatives
D1 | D2 | ... | Dn
islub(D1, D2, ..., Dn)
.
...where lub
is Least Upper Bound as defined here.
If you want to use anything that's specific to Exception1
or Exception2
, use separate catch
blocks:
} catch (Exception1 e) {
// Something using features of Exception1
} catch (Exception2 e) {
// Something using features of Exception2
}
If info
exists on both Exception1
and Exception2
, refactor them so that info
exists on a common ancestor class of them:
class TheAncestorException extends Exception {
public void info() { // Or possibly make it abstract
// ...
}
}
class Exception1 extends TheAncestorException {
// Optionally override `info` here
}
class Exception2 extends TheAncestorException {
// Optionally override `info` here
}
...so the compiler can give e
the type TheAncestorException
and make info
accessible.