Есть ли причина не использовать ключевое слово 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
.