В то время опробовать несколько поймать особенность , которую я нашел в моем 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()
компилируется?
Ответы:
Тип выражения
есть
Exception
, так как это общий супертипExcep1
иExcep2
.Однако вы не ловите
Exception
, поэтому компилятор жалуется на это.Если вы поймаете
Exception
, он пройдет компиляцию:Я попытался найти запись JLS, которая объясняет тип условного троичного выражения в вашем примере.
Все, что я мог найти, было то, что это конкретное выражение 15.25.3. Условное выражение .
Я не совсем уверен, считается ли это выражением поли или отдельным выражением. Я думаю, что это автономно (поскольку поли-выражения включают контекст присваивания или контекст вызова, и я не думаю, что
throw
оператор считается одним из них).Для автономного выражения: «Если второй и третий операнды имеют одинаковый тип (который может быть нулевым типом), то это тип условного выражения».
В вашем случае, второй и третий операнды имеют три общих типа -
Object
,Throwable
иException
- тип выражения должен быть один из двух последних, так как , «Выражение в вбрасывания заявление должно либо обозначать переменную или значение ссылочного типа который присваивается (§5.2) типу Throwable. "Похоже, что компилятор выбирает наиболее определенный общий тип (
Exception
), и, следовательно,catch (Exception e)
решает ошибку компиляции.Я также попытался заменить ваши два пользовательских исключения двумя подклассами
IOException
, и в этом случаеcatch (IOException e)
решается ошибка компиляции.источник
Excep1
илиExcep2
. Это может быть только такException
.Вы путаете компилятор с этой строкой:
Компилятор видит, что результатом выражения (слева от throw) является общий суперкласс между Except1 и Except2, который является Exception, и, следовательно, эффективный тип, который вы генерируете, становится Exception. Оператор catch не может определить, что вы пытаетесь выбросить Excep1 или Except2.
источник
Java ограничивает вас перехватом или объявлением всех типов исключений, которые может выдавать метод,
Он ищет общего родителя для обоих (/ всех) исключений и ожидает, что вы перехватите или объявите как броски, например, если
Excep1
расширяетThrowable
вам также придется ловить ThrowableВ первом случае Java уверен, что вы бросаете
Excep1
илиExcep2
источник