Ответ 1
Такое поведение появляется только на Java 1.7. При компиляции с 1.6 я получаю следующее сообщение об ошибке компилятора:
c:\dev\src\misc>javac -source 1.6 Main.java
warning: [options] bootstrap class path not set in conjunction with -source 1.6
Main.java:22: error: unreported exception Exception; must be caught or declared
to be thrown
throw e;
^
1 error
1 warning
Но с Java 1.7 он компилируется.
c:\dev\src\misc>javac -source 1.7 Main.java
c:\dev\src\misc>
... Пока я не выброшу Exception
в блок try
:
public static void throwsOrNotThrowsThatsTheQuestion() {
try {
// Any processing
throw new IOException("Fake!");
} catch (Exception e) {
throw e;
}
Компиляция...
c:\dev\src\misc>javac -source 1.7 Main.java
Main.java:22: error: unreported exception IOException; must be caught or declare
d to be thrown
throw e;
^
1 error
Похоже, что Java 1.7 достаточно умен, чтобы обнаружить тип Exception
(s), который может быть брошен, анализируя блок-код try
, где в 1.6 только что увидел throw e;
типа Exception
и дал ошибка только для этого.
Изменив его, чтобы выбросить RuntimeException
, он скомпилировал его, как и ожидалось, потому что, как всегда, unchecked Exception
не требует предложения throws
:
public static void throwsOrNotThrowsThatsTheQuestion() {
try {
// Any processing
throw new RuntimeException("Fake!");
} catch (Exception e) {
throw e;
}
Компиляция...
c:\dev\src\misc>javac -source 1.7 Main.java
c:\dev\src\misc>
Объяснение
Вот что происходит:
В Java 7 введена более инклюзивная проверка типов. Цитирование...
Рассмотрим следующий пример:
static class FirstException extends Exception { }
static class SecondException extends Exception { }
public void rethrowException(String exceptionName) throws Exception {
try {
if (exceptionName.equals("First")) {
throw new FirstException();
} else {
throw new SecondException();
}
} catch (Exception e) {
throw e;
}
}
В этом примере try block может вызвать либо FirstException, либо SecondException. Предположим, вы хотите указать эти типы исключений в предложении throws объявления метода rethrowException. В выпусках до Java SE 7 вы не можете этого сделать. Поскольку параметр исключения в предложении catch, e, является типом Exception, а блок catch восстанавливает параметр исключения e, вы можете указать только тип исключения Exception в предложении throws декларации метода rethrowException.
Однако в Java SE 7 вы можете указать типы исключений FirstException и SecondException в предложении throws в объявлении метода rethrowException. Компилятор Java SE 7 может определить, что исключение, вызванное выражением throw, должно быть получено из блока try, и единственными исключениями, которые были выбраны блоком try, может быть FirstException и SecondException. Несмотря на то, что параметр исключения в предложении catch, e, является типом Exception, компилятор может определить, что он является экземпляром либо FirstException, либо SecondException:
(акцент мой)
public void rethrowException(String exceptionName)
throws FirstException, SecondException {
try {
// ...
}
catch (Exception e) {
throw e;
}
}