can you tell me the static type of an exception in a multiple exception catch clause?

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:

  • Since both exceptions extend SuperException, you can call the SuperException method.
  • Since both exceptions implement interface Foo, you can call the Foo method.
  • The effective type is not SuperException, because then you couldn’t call Foo methods, and it is not Foo, because then you couldn’t call SuperException methods.
  • The effective type is truly a union of the nearest common super types, which really means all common super types.
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.

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top