#java #final #idioms
#java #Финал #идиомы
Вопрос:
Я хочу создать result
переменную final
, как мне структурировать этот код, чтобы он компилировался чисто? Я знаю, что делал это в прошлом, но я не могу вспомнить, как я структурировал это, чтобы заставить это работать.
Следующий код является straw man
примером, код, который я пытаюсь очистить, намного сложнее, это просто обобщение сути того, чего я пытаюсь достичь.
private boolean someMethod()
{
final boolean resu<
try
{
// do the logic here that might throw the following
// exceptions
}
catch (final IOException ioe)
{
result = false;
}
catch (final ClassNotFoundException cnfe)
{
result = false;
}
return resu<
}
Я не могу поместить result = true
в try
блок, потому что он не будет компилироваться с обоими блоками catch, жалующимися на то, что конечная переменная, возможно, уже назначена.
Я не могу поместить это в finally
блок, потому что это вызвало бы те же жалобы, что и в try
блоке?
Я хочу иметь возможность устанавливать result =
один и только один раз.
Итак, что вы устанавливаете result = true;
, чтобы заставить ее скомпилироваться чисто?
Комментарии:
1. Зачем создавать локальную переменную
final
?2. Я делаю все
final
настолько, насколько это возможно, потому что это значительно упрощает отладку, документирует намерение назначить переменную один и только один раз , а также является подсказкой по оптимизации для компилятора в большинстве случаев. Я не собираюсь спорить с этим аспектом, я знаю , что создание как можно большего количества ссылок на переменныеfinal
значительно повышает качество базы кода.3. @Джаррод Роберсон: Для меня в данном случае эта «оптимизация» снижает качество кода (то есть читаемость). Нет причин объявлять
result
какfinal
, особенно когда это сделает ваш метод излишне более сложным. В остальном, кроме этого случая, я полностью согласен с вами. 🙂4. это соломенный ответ на вопрос, на самом деле это не тот код, который я пытаюсь заставить работать так, как я хочу, это не усложняет его, это делает его более читаемым, и компилятор поймает ошибки, если другие места в моем коде, которые должны установить это, попытаются переписать его.
5. компилятор отловит ошибки, если другие места в моем коде, которые должны установить это, попытаются перезаписать это ? ЭТО ЛОКАЛЬНАЯ ПЕРЕМЕННАЯ!
Ответ №1:
Намного проще не задавать переменную.
private boolean someMethod() {
try {
// do the logic here that might throw the following
return true;
} catch (IOException ioe) {
// handle IOE
} catch (ClassNotFoundException cnfe) {
// handle CNFE
}
return false;
}
Комментарии:
1. Это то, о чем я тоже думал. Зачем устанавливать конечную переменную, которую вы просто собираетесь вернуть? исходный пример мне не понравился с точки зрения дизайна.
2. это решение цели, которой я пытался достичь ,
return
в несколькихcatch
предложениях нехорошо, и неизменяемыйresult
тоже нехорош. Читая этот ответ, я теперь вспоминаю, что именно такого подхода я придерживался в прошлом, спасибо, что освежили мою память.
Ответ №2:
Пытаться использовать final
для принудительного применения «назначить ровно один раз» всегда сложно. Вы можете использовать вторую переменную:
private boolean someMethod()
{
boolean res;
try
{
// do the logic here that might throw the following
// exceptions
}
catch (final IOException ioe)
{
res = false;
}
catch (final ClassNotFoundException cnfe)
{
res = false;
}
final boolean result = res;
return resu<
}
Но реальный вопрос в том, почему бы просто не удалить final
квалификатор?
Комментарии:
1. Либо это, либо удалите
try-catch
блок и сделайтеsomeMethod
throwIOException
иClassNotFoundException
.2. в документации указано, что это должно быть установлено только один и только один раз, это действительно затрудняет ошибки и помогает в отладке.
3. этот ответ не достигает моей цели. Я не хочу загрязнять остальной мой код исключениями, которые не связаны с его работой
4. @Jarrod — Я не думаю, что анализ потока, выполняемый компилятором, позволит вам выполнять такого рода присваивание в блоках catch. Можно было бы возразить, что это должно быть возможно, но это просто не так. Я бы предложил не спорить с мэрией по этому поводу и просто заменить
final
объявление простым комментарием над объявлением.
Ответ №3:
Вы не можете переназначить значение final
переменной, поэтому это невозможно.
редактировать: Также противоречит желанию объявлять переменную, которая является локальной для метода, как final
и также изменять значение в том же методе — зачем вообще нужно объявлять ее как final
в этом методе?
Комментарии:
1. Я ни на что ее не устанавливал, я не пытаюсь ее переназначать, я пытаюсь назначить ее только один раз , либо на
true
, либоfalse
на.2. Но
final
означает, что вы можете назначить только один раз в том же операторе, что и объявление — таким образом, оно не может быть объявлено, а затем назначено в блоке, подобном этому. Почему бы просто не удалитьfinal
модификатор из объявления, учитывая, что это только локальная переменная?
Ответ №4:
Если вы объявляете локальную переменную как final
внутри метода, то значение этой переменной не может быть изменено внутри метода.
Удалите final
из объявления result
или вообще избавьтесь от result
локальной переменной и возвращайте непосредственно из catch
блоков и конца метода.
Комментарии:
1. возврат изнутри кучи
catch
блоков — ужасная практика.2. возврат из нескольких мест в методе — плохая практика с самого начала, это обратная сторона
GOTO
, таким образом, возврат из нескольких блоков catch — плохая практика.3. Интересное чтение, спасибо. Однако это был не самый важный момент моего ответа, который заключался в том, чтобы полностью избавиться от
final
или удалитьresult
local, как Питер предложил в своем принятом ответе.