reference type of exception issue in multi-catch b

2020-04-16 18:37发布

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.

3条回答
Summer. ? 凉城
2楼-- · 2020-04-16 19:03

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 is lub(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.

查看更多
爷、活的狠高调
3楼-- · 2020-04-16 19:13
catch (Exception1 | Exception2 e) {....}

Here e is reference variable of both Exception1 and Exception2. So at compile time e.info(); will throw exception since info() is not there for Exception2.

Better to use separate catch block for each since both classes don't have same method info().

} catch (Exception1 e) {
            e.info();  
            System.out.println(e);  
        } catch (Exception2 e) {
            System.out.println(e);
        }
查看更多
叛逆
4楼-- · 2020-04-16 19:14

The multi-catch seems to be your problem. You (the compiler) can only access methods which are defined on the common ancestors. Of course, "e" will be an Exception1 during runtime, but the compiler just cannot assume that, cause it could as well be an Exception2. Better create a catch block for both Exception1 and Exception2.

查看更多
登录 后发表回答