Зачем использовать ключевое слово finally?
Я понимаю, для чего используется ключевое слово "finally" на разных языках, однако я с трудом понимаю, почему вы бы использовали его, если бы не было предпочтения форматирования по вкусу.
Например, в PHP:
try {
possibleErrorThrownFunction();
}
catch (CustomException $customException) {
// handle custom error
}
catch (Exception $exception) {
// handle the error
}
finally {
// run this code every single time regardless of error or not
}
Какая разница между тем, что делает этот код, и этим?
try {
possibleErrorThrownFunction();
}
catch (CustomException $customException) {
// handle custom error
}
catch (Exception $exception) {
// handle the error
}
// run this code every single time regardless of error or not
Разве эта последняя строка не всегда запускается из-за ошибки? В таком случае, нет никакого случая, чтобы действительно использовать finally
, если вы просто не хотите поддерживать форматирование в стиле кода?
Пример случая, когда инструкция finally
необходима и отлична от простого размещения кода после операторов try/catch, будет полезна, если я что-то здесь упустил.
Ответы
Ответ 1
Короткий ответ
Блоки Finally
гарантированно будут работать независимо от того, что происходит внутри блоков try
и catch
, до того, как произойдет сбой программы.
Это как бы объяснено здесь: https://www.php.net/manual/en/language.exceptions.php хотя объяснение не очень подробное.
Немного подробнее
Один из примеров, который приходит мне на ум, - это если вы имеете дело с потоками ввода/вывода или чем-то подобным, что должно быть закрыто после использования, чтобы избежать утечки памяти. Чтобы использовать ваш пример:
try {
memoryUser.startReading(someFileOrSomething);
}
catch (CustomException $customException) {
// handle custom error
}
catch (Exception $exception) {
// handle the error
invisibleBug.whoops(); // i.e. something goes wrong in this block
}
memoryUser.Close(); // because something went wrong in the catch block,
// this never runs, which, in this case, causes a memory leak
В этом случае перенос memoryUser.Close();
в блок finally
обеспечит выполнение этой строки до взрыва остальной части программы, предотвращая утечку памяти даже в случае другого катастрофического сбоя.
TL; DR
Поэтому большую часть времени люди помещают туда блок finally, чтобы обеспечить выполнение важных строк, даже если они что-то пропустили в блоках перехвата. Это то, как я всегда видел это.
Надеюсь, это поможет :)
Ответ 2
Что особенного в блоке finally {}
, так это то, что он всегда будет работать в конце блока try {}
.
Он запустится, если код в блоке try {}
завершится успешно.
Он запустится, если код в блоке try {}
сгенерирует исключение, которое было перехвачено catch {}
. (finally {}
работает после catch {}
.)
Он будет работать, если код в блоке try {}
выдает исключение, которое не было обработано ни одним блоком catch {}
, или если его вообще не было. (Блок finally {}
выполняется до того, как исключение передается вызывающей стороне.)
Он будет работать, если код в блоке try {}
выдает исключение, а код в catch {}
выдает другое исключение (или сбрасывает то же исключение).
Он даже запустится, если код в блоке try {}
или в блоке catch {}
использует return
. (Как и в случае с неперехваченным исключением, finally {}
запускается до фактического возврата из функции.) Блок finally {}
может даже использовать сам return
, и его возвращаемое значение переопределит значение, которое другой блок попытался вернуть!
(Существует один крайний случай, когда блок finally {}
не будет запущен, и это, если весь процесс будет уничтожен, например, в результате уничтожения или вызова exit()
или die()
.)