Java: значение catch (окончательное SomeException e)? - PullRequest
32 голосов
/ 19 августа 2010

Что final делает в следующем выражении Java?

catch (final SomeExceptionType e)

Ответы [ 4 ]

31 голосов
/ 19 августа 2010

В основном это означает:

Перехватывает «SomeExceptionType» в переменную «e» с обещанием, что мы не будем назначать другое исключение для «e» во время обработки исключения.

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

Тем не менее, возможно, этот блок активно поддерживается командой разносторонних людей, и один просто хотел быть ОЧЕНЬ уверенным в том, что e был первоначально захваченнымисключение.

---- Отредактировано в ответ на комментарий ----

Я не могу придумать действительно веской причины для этого.Так как «e» не является членом (статическим или иным), имя «e» не будет использоваться посткомпиляцией файла класса.Еще один способ заявить, что при вводе блока обработки исключений байт-кода JVM объект не будет назначен ни одному из имен элементов, доступных в кадре обработки JVM, он будет помещен во внутренний стек обработки потокатекущий кадр.

Даже если бы два потока имели доступ к одному и тому же объекту, каждый поток имел бы свой собственный кадр, поэтому компилятор удалил имя "e" из внутреннего стека одного кадра, который не мог бы быть изменен другим потоком.

Имея это в виду, единственное преимущество объявления финала "e" - это убедиться, что будущие кодеры случайно не установят "e" после входа в блок.Возможно, они хотели сделать код более надежным в многопоточной среде, но временные переменные (с именами, которые допустимы только в блоке) не имеют имен после компиляции, они помещаются в стек фрейма.

Вот почему

public int safe() {
  int x = 5;
  x = x + 5;
  return x;
}

обычно считается поточно-ориентированным, поскольку он делает это (в псевдобайтном коде)

(In the thread's current frame)
push 5
push 5
add integers
return

Хотя это не поточно-ориентированное

int x = 5;

public void unsafe() {
  x = 5;
  x = x + 5;
  return x;
}

потому что он делает это

(in the thread's current frame)
push "this"
push 5
set member x
push "this"
get member x
push 5
add integer
set member x
get member x
return

Последний байт-код делает очевидным, что чередование двух потоков создает межпотоковые связи с использованием члена x a посредника, в то время как первый блок кода не можетиметь связь между потоками, потому что нет посредника.

11 голосов
/ 19 августа 2010

В настоящее время это означает final почти так же, как любая локальная переменная, за исключением того, что она всегда «определенно назначена».

В последних сборках JDK7 изменение языка Project Coin позволяет ему указывать на степень неявной статической типизации. Один catch может перехватить несколько различных проверенных исключений по общему базовому типу и перебросить с включающим контекстом, имеющим только перехват, или объявить те исключения, которые (статически говоря) могут быть выброшены в try. (См. Ссылку для лучшего объяснения.)

5 голосов
/ 10 марта 2016

Вопрос "Что делает final?"адресовано в других ответах на этот вопрос, и здесь , здесь и здесь .Но в контексте try-catch блок Спецификация языка Java (JLS) §4.12.4 заявляет (выделение мое):

  • Ресурс оператора try-with-resources (§14.20.3) и параметр исключения для предложения multi-catch (§14.20) неявно объявлено окончательным .
  • Параметр исключения из предложения uni-catch (§14.20) может быть фактически окончательным, вместо того, чтобы быть явно объявленным окончательным.Такой параметр никогда не объявляется окончательно .

В предложении с несколькими перехватами :

Добавление final ключевое слово для выражения multi-catch просто делает явным тот факт, что variable неявно является окончательным.В общем, всякий раз, когда ключевое слово final передает дополнительную информацию, которая помогает сделать ваш код более читабельным / поддерживаемым, используйте его.

В предложении uni-catch

С другой стороны, параметр исключения в предложении uni-catch равен never неявно окончательный.Таким образом, использование ключевого слова final в предложении uni-catch предотвращает следующее:

try {
     throw new Exception();
catch (Exception e){
    e = null;
    e.printStackTrace(); //throws a NullPointerException
}

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

  1. Если блок захвата является более сложным, возможна случайная переназначение.(Хотя, если блок catch сложный, вы, вероятно, делаете это неправильно.)
  2. Чтобы предотвратить проблемы, возникающие во время обслуживания кода.Добавление final к переменной-исключению обеспечит переопределение при компиляции, , а не время выполнения

Как общее правило, используйте ключевое слово final в предложение uni-catch аналогично тому, как вы используете ключевое слово final для параметра метода :

JLS§4.12.4 : Объявление переменной final может служить полезной документацией, что ее значение не изменится и поможет избежать ошибок программирования.

2 голосов
/ 19 августа 2010

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

Это важное свойство, поскольку для сопровождающего это означает, что эта конкретная переменная будет иметь это конкретное значение везде, где она используется, и нет необходимости отслеживать, где она изменяется.Это признано настолько полезным, что действие «Очистить» в Eclipse позволяет добавлять «окончательный», где это возможно, и я считаю, что вы видите результат такой автоматической очистки,потому что большинство программистов-людей держат блок catch коротким, поэтому такая индикация не нужна.

...