Есть ли причина не использовать ключевое слово final при перехвате исключения?

В некоторых примерах классов BlackBerry Java я видел код, как показано ниже:

try
{
    // stuff that will throw an exception
}
catch(final Exception e)
{
    // deal with it
}

Я предполагаю, что final предназначен для производительности. В соответствии с заголовком, поскольку редко (когда-либо?) Была какая-то причина для изменения уже Exception, если они всегда были final?

Если это так, разве это не может быть сделано компилятором? Или это делается компилятором и добавление final вручную не оказывает никакого влияния?

Ответ 1

Спецификация языка Java 11.2.2 делает разницу между окончательными и не финальными исключениями:

Оператор throw (§14.18), у которого выведенное выражение имеет статический тип E и не является окончательным или эффективным окончательным параметром исключения, может выбросить E или любой класс исключения, который может вызвать брошенное выражение.
[...]
Оператор throw, чье выраженное выражение является окончательным или эффективным окончательным параметром исключения в предложении catch, может генерировать класс исключений E iff:

  • E - это класс исключений, который может выполнить блок try из оператора try, который объявляет C; и
  • E - это присвоение, совместимое с любым из классов C catchable exception; и
  • E не является присвоением, совместимым с любым из захватывающих классов исключений клаунов catch, объявленных слева от C в том же самом заявлении try.

Интересно, что JLS 14.20 также говорит:

В предложении uni-catch параметр исключения, который не объявлен окончательным (неявно или явно), считается эффективным окончательным, если он никогда не встречается в своей области действия в качестве левого операнда оператора присваивания.

Другими словами, если вы не переназначаете e вашего оператора catch (например, e = new SomeOtherException();), он неявно объявляется окончательным.

Поэтому я могу только заключить, что это не имеет значения, если исключение не будет изменено в блоке catch, и единственным примером, который я могу придумать, является:

public void method1() throws IOException {
    try {
        throw new IOException();
    } catch (Exception e) { // e is not modified in catch => implicitly final
        throw e; //compiles OK
    }
}

//it works because method1 is semantically equivalent to method2:
public void method2() throws IOException {
    try {
        throw new IOException();
    } catch (final Exception e) {
        throw e;
    }
}

public void method3() throws IOException {
    try {
        throw new IOException("1");
    } catch (Exception e) {
        e = new IOException("2"); //e modified: not implicitly final any more
        throw e; //does not compile
    }
}

Ответ 2

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

Использование final для предложения catch вряд ли поможет значительно, так как a) значение гарантировано будет установлено b) используемый с ним код должен быть коротким, c) его очень редко можно модифицировать его.

Нет ничего, что мешает вам делать это.

Ответ 3

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

Ответ 4

Я сомневаюсь, что final действительно даст какое-либо преимущество в производительности, потому что экземпляр исключения является блочным локальным (вот действительно хороший ответ, объясняющий его fooobar.com/questions/17740/...).

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

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

По сути, я бы сказал, что это вопрос предпочтения. Некоторым может понравиться то, что другие не могут.

Ответ 5

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

Также существует проверка соответствия в PMD анализаторе кода, которая проверяет, что все возможное объявлено как final.