Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the static type of an exception in a multiple exception catch clause? [duplicate]

Tags:

java

types

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?

like image 498
neilO Avatar asked Oct 28 '20 15:10

neilO


People also ask

How do you handle different types of exceptions using multiple catch statements?

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.

Can you catch 2 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.

Is there a way to catch multiple exceptions at once and without code duplication?

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.

How do you handle multiple exceptions in catch block?

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.


1 Answers

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.

like image 111
Andreas Avatar answered Oct 17 '22 01:10

Andreas