Есть ли смысл делать «попробуй-наконец» без «ловушки»?


127

Я видел такой код:

    try
    {
        db.store(mydata);
    }
    finally
    {
        db.cleanup();
    }

Я думал, tryчто должно быть catch?

Почему этот код делает это именно так?


1
он обеспечивает очистку, как упоминалось в других ответах, особенно для дескрипторов файлов fopenили подключения к БД (также в PHP)
MediaVince

Ответы:


182

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

public void yourOtherMethod() {
    try {
        yourMethod();
    } catch (YourException ex) {
        // handle exception
    }
}    

public void yourMethod() throws YourException {
    try {
        db.store(mydata);
    } finally {
        db.cleanup();
    }
}

17
обычно используется с блокировками, например: lock.lock (); попробуйте {/ * заблокированные * /} наконец {lock.unlock ()}
минут

Что произойдет, если в конце концов возникнет исключение?
barth

1
@barth Если catchблока нет, то выброшенное исключение finallyбудет выполнено перед любым исключением в tryблоке. Итак, если есть два исключения, одно tryи одно, finallyединственное исключение, которое будет выбрано, - это одно внутри finally. Это поведение отличается от PHP и Python, так как оба исключения будут генерироваться одновременно на этих языках, и порядок исключений - tryсначала, затем finally.
Дождь

72

Это потому, что программист хотел убедиться, что он db.cleanup()вызывается, даже если код внутри блока try генерирует исключение. Любые исключения не будут обрабатываться этим блоком, но они будут распространяться вверх только после выполнения блока finally.


23
+1 Совершенно верно. tryТолько там , чтобы позволить finally. Исключений не улавливают.
zockman

2
+1 за разъяснение того, что исключение продолжается вверх по стеку, пока не будет обнаружено. Спасибо
Code Jockey

20

Почему этот код делает это именно так?

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

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

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


2

Блок finally гарантирует, что даже когда генерируется исключение RuntimeException (возможно, из-за какой-либо ошибки в вызываемом коде), db.cleanup() вызов будет выполнен.

Это также часто используется для предотвращения слишком большого количества вложений:

try
{
    if (foo) return false;
    //bla ...
    return true;
}
finally
{
    //clean up
}

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


0

Код делает это, чтобы гарантировать, что база данных закрыта.
Обычно для этого нужно поместить весь код доступа к базе данных в блок try, а затем поместить вызов для закрытия базы данных в блок finally.
То, как работает try ... finally, означает, что код в блоке try выполняется, а код в блоке finally выполняется, когда он завершается ... несмотря ни на что.
Если не считать того, что компьютер выдернут из стены, то наконец выполнится.
Это означает, что даже если вызывается исключение и для выполнения метода требуется три года, оно все равно попадет в блок finally, и база данных будет закрыта.


0

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

Блок finally всегда выполняется, независимо от того, выброшено ли исключение.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.