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

127

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

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

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

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

glanden
источник
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
}

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

FRotthowe
источник
0

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

chustar
источник
0

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

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

ТОНКИЙ ВАЗИ
источник