Перехват нескольких исключений в Java-8

71

В то время опробовать несколько поймать особенность , которую я нашел в моем m1()методе все работает отлично , как и ожидалось.

Однако в m2()том же коде не компилируется. Я только что изменил синтаксис, чтобы уменьшить количество строк кода.

public class Main {

    public int m1(boolean bool) {
        try {
            if (bool) {
                throw new Excep1();
            }
            throw new Excep2();
            //This m1() is compiling  abs fine.
        } catch (Excep1 | Excep2 e) {
            return 0;
        }
    }

    public int m2(boolean b) {
        try {
            throw b ? new Excep1() : new Excep2();
            //This one is not compiling.
        } catch (Excep1 | Excep2 e) {
            return 0;
        }
    }

    private static interface I {
    }

    private static class Excep1 extends Exception implements I {
    }

    private static class Excep2 extends Exception implements I {
    }
}

Почему метод не m2()компилируется?

джокер
источник
22
Какую ошибку компиляции вы получаете?
Гэвин

Ответы:

79

Тип выражения

b ? new Excep1() : new Excep2()

есть Exception, так как это общий супертип Excep1и Excep2.

Однако вы не ловите Exception, поэтому компилятор жалуется на это.

Если вы поймаете Exception, он пройдет компиляцию:

public int m2(boolean b) {
    try {
        throw b ? new Excep1() : new Excep2();
    } catch (Exception e) {
        return 0;
    }
}

Я попытался найти запись JLS, которая объясняет тип условного троичного выражения в вашем примере.

Все, что я мог найти, было то, что это конкретное выражение 15.25.3. Условное выражение .

Я не совсем уверен, считается ли это выражением поли или отдельным выражением. Я думаю, что это автономно (поскольку поли-выражения включают контекст присваивания или контекст вызова, и я не думаю, что throwоператор считается одним из них).

Для автономного выражения: «Если второй и третий операнды имеют одинаковый тип (который может быть нулевым типом), то это тип условного выражения».

В вашем случае, второй и третий операнды имеют три общих типа - Object, Throwableи Exception- тип выражения должен быть один из двух последних, так как , «Выражение в вбрасывания заявление должно либо обозначать переменную или значение ссылочного типа который присваивается (§5.2) типу Throwable. "

Похоже, что компилятор выбирает наиболее определенный общий тип ( Exception), и, следовательно, catch (Exception e)решает ошибку компиляции.

Я также попытался заменить ваши два пользовательских исключения двумя подклассами IOException, и в этом случае catch (IOException e)решается ошибка компиляции.

Эран
источник
11
@Smile тип троичного условного выражения должен быть общим для 2-го и 3-го операндов. Поэтому это не может быть Excep1или Excep2. Это может быть только так Exception.
Эран
2
Последний пункт в п. 15.25.3 имеет ответ: «В противном случае второй и третий операнды имеют типы S1 и S2 соответственно. Пусть T1 будет типом, который следует из применения преобразования в бокс для S1, и пусть T2 будет типом, который приводит к от применения преобразования в бокс к S2. Тип условного выражения является результатом применения преобразования захвата (§5.1.10) к lub (T1, T2). " lub здесь - наименее верхняя граница, которая является ближайшим общим супертипом, который разделяют типы двух выражений.
Амаллой
22

Вы путаете компилятор с этой строкой:

throw b ? new Excep1() : new Excep2();

Компилятор видит, что результатом выражения (слева от throw) является общий суперкласс между Except1 и Except2, который является Exception, и, следовательно, эффективный тип, который вы генерируете, становится Exception. Оператор catch не может определить, что вы пытаетесь выбросить Excep1 или Except2.

GideonleGrange
источник
4

Java ограничивает вас перехватом или объявлением всех типов исключений, которые может выдавать метод,

Он ищет общего родителя для обоих (/ всех) исключений и ожидает, что вы перехватите или объявите как броски, например, если Excep1расширяетThrowable вам также придется ловить Throwable

В первом случае Java уверен, что вы бросаете Excep1илиExcep2

user7294900
источник