reference type of exception issue in multi-catch block

别等时光非礼了梦想. 提交于 2019-12-02 06:04:57

问题


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.


回答1:


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.




回答2:


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.




回答3:


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);
        }


来源:https://stackoverflow.com/questions/47282370/reference-type-of-exception-issue-in-multi-catch-block

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!