Java 7 - Точный бросок с окончательным исключением

В предыдущих версиях java, реорганизация исключения рассматривалась как бросание типа параметра catch.

Например:

public static void test() throws Exception{
    DateFormat df = new SimpleDateFormat("yyyyMMdd");
    try {
        df.parse("x20110731");
        new FileReader("file.txt").read();
    } catch (Exception e) {
        System.out.println("Caught exception: " + e.getMessage());
        throw e;
    }
}

В Java 7 вы можете уточнить об исключении, если вы объявите исключение final:

//(doesn't compile in Java<7)
public static void test2() throws ParseException, IOException{
    DateFormat df = new SimpleDateFormat("yyyyMMdd");
    try {
        df.parse("x20110731");
        new FileReader("file.txt").read();
    } catch (final Exception e) {
        System.out.println("Caught exception: " + e.getMessage());
        throw e;
    }
}

Мой вопрос. Документы говорят, что мне нужно объявить Exception final. Но если я этого не делаю, код выше все еще компилируется и работает. Я что-то упускаю?

Литература:

Монета проекта: многопользовательское и окончательное ретронирование
Добавить более гибкую проверку повторных исключений

Ответ 1

Я считаю, что я видел твит из Джоша Блоха, в котором говорилось, что "последнее" ограничение было отменено поздно. Я посмотрю, смогу ли я найти сообщение об этом, но я подозреваю, что любая "ранняя" документация, которую вы читаете, теперь неточна.

EDIT: я не могу найти точную запись "она изменилась", но в документах по Java 7 показан пример, когда он не является окончательным. Он говорит о том, что переменные исключений являются неявно окончательными, когда блок catch объявляет более одного типа, но немного отличается.

EDIT: теперь я нашел источник своей путаницы, но это внутренняя почтовая рассылка:( В любом случае, это не обязательно должно быть объявлено окончательным, но я считаю, что компилятор рассматривает это как неявно окончательный - просто как в сценарии с несколькими ловушками.

Ответ 2

Причина, по которой компиляция заключается в том, что исключение в объявлении uni catch, которое впоследствии не изменяется, неявно окончательно (JLS 14.20).

Итак, для вашего примера не компилировать, вам нужно каким-то образом изменить e, например:

public static void test2() throws ParseException, IOException {
    DateFormat df = new SimpleDateFormat("yyyyMMdd");
    try {
        df.parse("x20110731");
        new FileReader("file.txt").read();
    } catch (Exception e) {
        if (e instanceof ParseException) {
            e = new ParseException("Better message", 0);
        } else {
            e = new IOException("Better message");
        }
        System.out.println("Caught exception: " + e.getMessage());
        throw e; //does not compile any more
    }
}

Ответ 3

Без финала он все еще действителен java. Вы просто теряете пользу от того, чтобы быть "точным".