Ловлячи кілька винятків у 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) до лубу (T1, T2). " луб тут - Найменша верхня межа, яка є найближчим загальним супертипом, який мають два типи виразів.
amalloy

22

Ви плутаєте компілятор з цим рядком:

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

Компілятор бачить, що результатом виразу (зліва від кидка) є загальний суперклас між Except1 та Except2, що є винятком, і тому ефективний тип, який ви кидаєте, стає Винятком. Заява улову не може зрозуміти, що ви намагаєтеся кинути Excep1 або Except2.


4

Java обмежує вам ловити або оголошувати всі типи винятків, які може викидати метод,

Він шукає спільного батьків для обох (/ всіх) винятків, і очікує, що ви будете ловити або оголошувати як кидки, наприклад, якщо Excep1розширення Throwableвам доведеться ловити також Throwable

У першому випадку Java впевнений, що ви або кидаєте, Excep1абоExcep2

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.