In this code example, what's the static type of e
in the catch block?
try {
....
} catch(IOException | NumberFormatException e) {
//what's the static type of e in here? Is it Exception?
System.out.println(e.getClass());
}
It seems to be effectively Exception
, but when I hover over it in my IDE it says IOException | NumberFormatException
. Is this a special type that only applies to multiple exceptions in catch blocks or does it generalize to other types?
The Try Block If your code throws more than one exception, you can choose if you want to: use a separate try block for each statement that could throw an exception or. use one try block for multiple statements that might throw multiple exceptions.
When catching multiple exceptions in a single catch block, the rule is generalized to specialized. This means that if there is a hierarchy of exceptions in the catch block, we can catch the base exception only instead of catching multiple specialized exceptions.
In C#, You can use more than one catch block with the try block. Generally, multiple catch block is used to handle different types of exceptions means each catch block is used to handle different type of exception.
If a catch block handles multiple exceptions, you can separate them using a pipe (|) and in this case, exception parameter (ex) is final, so you can't change it. The byte code generated by this feature is smaller and reduce code redundancy.
TL;DR: The static type is the nearest common super class.
The Java Language Specification, section 14.20. The try
statement, says:
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 with a single class type is that class type.
The declared type of an exception parameter that denotes its type as a union with alternatives D1 | D2 | ... | Dn is lub(D1, D2, ..., Dn).
So, it's basically called a "union type", and doesn't exist elsewhere in the language.
UPDATE
The effective type is the union of the nearest common super types (class and/or interfaces), i.e. you can call any method that is common for all the alternatives.
The code below illustrates the following points:
SuperException
, you can call the SuperException
method.Foo
, you can call the Foo
method.SuperException
, because then you couldn't call Foo
methods, and it is not Foo
, because then you couldn't call SuperException
methods.try {
// some code throwing the exceptions
} catch (SubException1 | SubException2 e) {
e.methodInSuper(); // you can call the SuperException method
e.foo(); // you can call the Foo method
}
interface Foo {
void foo();
}
class SuperException extends Exception {
public void methodInSuper() {
// code here
}
}
class SubException1 extends SuperException implements Foo {
@Override
public void foo() {
// code here
}
}
class SubException2 extends SuperException implements Foo {
@Override
public void foo() {
// code here
}
}
UPDATE 2
To answer the exact question "what's the static type of the exception?", we need to look at the bytecode.
The bytecode of the catch clause of the above code is:
34: astore_1
35: aload_1
36: invokevirtual #33 // Method SuperException.methodInSuper:()V
39: aload_1
40: checkcast #38 // class Foo
43: invokeinterface #40, 1 // InterfaceMethod Foo.foo:()V
48: return
Exception table:
from to target type
0 34 34 Class SubException1
0 34 34 Class SubException2
As you can see, the single catch
clause registers 2 exceptions to be caught, directing both to the same code block. The call to SuperException.methodInSuper()
is done straight up. The call to Foo.foo()
is done after casting to Foo
. The compiled code can be consider equivalent to the follow, except it only catches the 2 subexceptions:
} catch (SuperException e) { // only catch SubException1 and SubException2
e.methodInSuper();
((Foo) e).foo();
}
Conclusion: The static type is the nearest common super class. Any additional common interfaces that is not defined by that super class are silently be handled by the compiler using casts.
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