Чому ми використовуємо нарешті блоки?


91

Наскільки я можу зрозуміти, обидва наведені нижче фрагменти коду слугуватимуть одній і тій же меті. Навіщо взагалі finallyблоки?

Код А:

try { /* Some code */ }
catch { /* Exception handling code */ }
finally { /* Cleanup code */ }

Код B:

try { /* Some code */ }
catch { /* Exception handling code */ }
// Cleanup code

Це не специфічно для C #, це питання .Net
Sruly

1
Більше не потрібно з java7: AutomaticResourceManagement, спробуйте (новий
ресурсDeclartion

Відповіді:


139
  • Що станеться, якщо буде викинуто виняток, з яким ви не працюєте? (Сподіваюсь, ви не ловите Throwable...)
  • Що станеться, якщо ви повернетеся зсередини блоку try?
  • Що станеться, якщо блок catch видає виняток?

finallyБлок гарантує , що однак вихід цього блоку ( по модулю кілька способів переривання всього процесу явно), то буде виконано. Це важливо для детермінованого очищення ресурсів.


48
Не обов'язково вірно; нарешті не буде виконано, якщо (1) є System.exit()виклик (2) у спробі є нескінченний цикл або один із блоків catch (3) Я
витягую

2
@Alon try {return 1; } нарешті {повтор 2; } Ви отримаєте 2
Dennis C

19
@NullUserException: Звідси біт "за модулем кілька способів ..."
Джон Скіт,

2
Джон Скіт живе тут, на stackoverflow, кожне питання схоже на дзвінок у двері, на який він повинен відповісти :)
naikus

1
У цій публікації розглядаються (рідкісні) умови, за яких нарешті НЕ БУДУТЬ закликані.
Candamir

13

Зауважте, що (принаймні на Java, можливо, також на C #), також можна мати tryблок без a catch, але з a finally. Коли в tryблоці трапляється виняток , код у finallyблоці запускається до того, як виняток буде викинуто вище:

InputStream in = new FileInputStream("somefile.xyz");
try {
    somethingThatMightThrowAnException();
}
finally {
    // cleanup here
    in.close();
}

7

Можливо, ви захочете помістити код, який ви хочете в будь-якому випадку виконати, незалежно від того, що відбувається у вашому блоці try або catch.

Крім того, якщо ви використовуєте багаторазовий catch і якщо ви хочете ввести якийсь загальний код для всіх блоків catch, це було б місце для розміщення, але ви не можете бути впевнені, що весь код в спробі був виконаний.

Наприклад:

conn c1 = new connection();
try {
    c1.dosomething();
} catch (ExceptionA exa) {
    handleexA();
    //c1.close();
} catch (ExceptionB exb) {
    handleexB();
    //c1.close();
} finally {
    c1.close();
}

1
Що робити, якщо я не використовую "нарешті", а замикаю з'єднання?
Істіаке Ахмед

5

Нарешті завжди виконується, де як ваш код після лову може і не бути.


1
чому ні! Якщо виняток обробляється належним чином, код буде виконаний остаточно.
Mohammad Nadeem

1
@Nadeem: Дивіться мою відповідь із трьох причин, що це може не відбутися.
Джон Скіт,

2

Навіть незважаючи на те, що наш додаток закрито примусово, ми будемо виконувати деякі завдання (наприклад, випуск пам'яті, закриття бази даних, блокування випуску тощо), якщо ви напишете ці рядки коду в finallyблок, він буде виконуватись, чи буде вилучено виняток або ні ...

Ваша програма може бути колекцією потоків, що Exceptionзавершує нитку, але не цілу програму, в цьому випадку finallyє більш корисною.

У деяких випадках finallyне виконується, наприклад JVM Fail, Thread terminate тощо.


1

Тому що вам потрібен цей код для виконання незалежно від будь-яких винятків, які можуть виникнути. Наприклад, вам може знадобитися очистити якийсь некерований ресурс (конструкція 'using' компілюється до блоку try / нарешті).


0

Бувають випадки, коли ви хочете виконати фрагмент коду, незважаючи ні на що. Незалежно від того, кинуто виняток чи ні. Потім один використовує finally.


0

finallyЗАВЖДИ виконується, якщо JVM не було вимкнено, finallyпросто надає метод розміщення коду очищення в одному місці.

Було б занадто нудно, якби вам доводилося вводити код очищення в кожен з catchблоків.


0

Якщо блок catch викидає будь-який виняток, тоді залишковий код не буде виконаний, отже, ми повинні написати finaly block.


0

нарешті, блок у Java може бути використаний для введення коду "очищення", такого як закриття файлу, закриття з'єднання тощо.


Блок нарешті не буде виконаний, якщо програма завершиться (викликом System.exit () або викликанням фатальної помилки, яка призводить до переривання процесу).


0

Все ще прокручуєте вниз? Ось вам!

Це питання дало мені важкий час назад.

try
{
 int a=1;
 int b=0;
 int c=a/b;
}
catch(Exception ex)
{
 console.writeline(ex.Message);
}
finally
{
 console.writeline("Finally block");
}
console.writeline("After finally");

що буде надруковано у вищезазначеному сценарії? Так, правильно вгадав:

  • напр. повідомлення - яким би воно не було (можливо, спроба ділення на нуль)

  • Нарешті блокувати

  • Після нарешті

    try
    {
        int a=1;
        int b=0;
        int c=a/b;
    }
    catch(Exception ex)
    {
        throw(ex);
    }
    finally
    {
        console.writeline("Finally block");
    }
    console.writeline("After finally");
    

Що це за друк? Нічого! Він видає помилку, оскільки блок catch викликав помилку.

У хорошій структурі програмування ваші винятки будуть спрямовані, в тому сенсі, що цей код буде оброблятися з іншого рівня. Для стимулювання такого випадку я вкладу спробувати цей код.

try
{    
 try
    {
     int a=1;
     int b=0;
     int c=a/b;
    }
    catch(Exception ex)
    {
     throw(ex);
    }
    finally
    {
     console.writeline("Finally block")
    }
    console.writeline("After finally");
}
catch(Exception ex)
{
 console.writeline(ex.Message);
}

У цьому випадку результат буде:

  • Нарешті блокувати
  • напр. повідомлення - яким би воно не було.

Зрозуміло, що коли ви ловите виняток і перекидаєте його знову на інші шари (функціонування), код після кидка не виконується. Це діє подібно до того, як працює повернення всередині функції.

Тепер ви знаєте, чому б не закрити свої ресурси на кодах після блоку catch, помістіть їх у блок нарешті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.