Використання "лову винятків" для поліпшення читабельності, добре чи погано?


9

У розділі Коли слід використовувати виняток у Прагматичному програмісті , книга пише, що замість:

retcode = OK;
     if (socket.read(name) != OK) {
      retcode = BAD_READ;
    }
     else {
      processName(name);
       if (socket.read(address) != OK) {
        retcode = BAD_READ;
      }
       else {
        processAddress(address);
         if (socket.read(telNo) != OK) {
          retcode = BAD_READ;
        }
         else {
          //  etc, etc...
        }
      }
    }
     return retcode;

вони віддають перевагу:

 retcode = OK;
     try {
      socket.read(name);
      process(name);
      socket.read(address);
      processAddress(address);
      socket.read(telNo);
      //  etc, etc...
    }
     catch (IOException e) {
      retcode = BAD_READ;
      Logger.log( "Error reading individual: " + e.getMessage());
    }
     return retcode;

просто тому, що це виглядає акуратніше. Я все за чистіший код, однак не зайвим є виняток із вузьким місцем продуктивності?

Я можу зрозуміти, що ми повинні відмовитись від мізерної оптимізації для більш чистих кодів (принаймні у 99% разів), однак, наскільки я знаю, вилучення винятків належать до класу коду, у якого помітна затримка у виконанні. Отже, мені було цікаво, яке виправдання, що другий фрагмент коду віддається перевазі перед першим кодом?

А точніше, якому коду ви б віддали перевагу?


перейшов з Code Review, оскільки його питання найкращої практики, а не питання перегляду коду
Вінстон Еверт

1
IMO, якщо ви очікуєте, що зможете прочитати ці значення з сокета, то IOEx є винятковою.
Стівен Еверс


Ви вимірювали?

@ ThorbjørnRavnAndersen, звичайно, я читав книгу і не маю справжнього "тестового випадку" для вимірювання .. але якщо ми все-таки вимірюємо це надуманим кодом, тоді, очевидно, є покарання за продуктивність
Pacerier

Відповіді:


18

Винятки, як правило, лише повільніше, якщо вони насправді кинуті. Зазвичай винятки в таких ситуаціях рідкісні, тому це не те, про що слід турбуватися. Вам слід по-справжньому хвилюватися щодо виконання винятків, лише якщо вони відбуваються постійно і, таким чином, є важливим фактором.

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


4
Погоджено, я ненавиджу бачити коди помилок мовою, яка має винятки. Більшу частину часу ви повинні ловити, вести журнал, повторно скидати, не порушуючи стек викликів. І більшість часу не має значення, чи випадок "винятку" повільніше. У додатку є проблема, знайдіть час, щоб правильно її впоратися. Поки виняток є винятковим і не є частиною звичайної роботи програми чи щасливого шляху, це зазвичай не запах коду.
CaffGeek

До речі, мені було цікаво, як ми виправдовуємо EOFException, який DataStreams використовує для виявлення кінця рядка (кінець рядка не є винятковим), як показано в docs.oracle.com/javase/tutorial/essential/io/datastreams.html ?
Pacerier

@Pacerier, це може бути винятково. Вичерпання введення рядка може вказувати на погані дані або щось жахливо неправильне. Я підозрюю, що цільове використання - проаналізувати декілька полів поза рядком.
Вінстон Еверт

@Downvoter, якщо у вас є проблема з відповіддю, будь ласка, поясніть!
Вінстон Еверт

5

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

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

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


5

Я можу зрозуміти, що ми повинні відмовитись від мізерної оптимізації для більш чистих кодів (принаймні у 99% разів), однак, наскільки я знаю, вилучення винятків належать до класу коду, у якого помітна затримка у виконанні.

Звідки ви це знаєте? Як ви визначаєте "помітну затримку"?

Це саме такий неясний (і зовсім неправильний) міф про продуктивність, який призводить до марних передчасних оптимізацій.

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


Я походжу з .NET, тому вибачте мене про знання Java, але я особисто зазнав винятків у .NET, що спричинило божевільні затримки (величина секунд), які були виправлені видаленням "коду вилучення-виключення" ..
Pacerier

@Pacerier, серйозно? величина секунди? Я здогадуюсь, можливо, це було винятком багатьох винятків? Тоді я міг це бачити.
Вінстон Еверт

3
@Pacerier: Якщо винятки спричиняють божевільні затримки, очевидно, що викликає їх, не є винятковим, і тому слід поводитися з іншими способами. Жодна система не потребує секунд, щоб обробляти виняток, і я вважаю, що Microsoft достатньо компетентний, щоб уникнути цього.
Девід Торнлі

5

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

Що стосується вашої вистави, це стосується більш прямого напряму, я думаю, що вам потрібно зберегти відчуття масштабу речей. Кидання / лов винятку за цих обставин, швидше за все, набере порядок мікросекунди. Коли управління потоком йде, це відбувається повільно - у багато разів повільніше, ніж звичайні ifтвердження, про це не йдеться.

У той же час пам’ятайте, що те, що ви тут робите, - це читання даних з мережі. При 10 мегабітах в секунду (повільно для локальної мережі, але досить швидко, як і підключення до Інтернету), це в тому ж порядку, що і час для читання одного байта інформації.

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

У цьому випадку, коли буде викинуто виняток, ваші записи даних у журнал. Враховуючи характер ведення журналів, дуже ймовірно, що ви пропрасуєте цей висновок, як тільки ви його записуєте (щоб не втратити його). Запис на диск - це (знову ж таки) досить повільна робота - вам потрібен досить швидкий корпоративний SSD, щоб навіть потрапити в діапазон десятків тисяч IOP / секунди. Диск, що використовується для ведення журналу, може бути легко обмежений чимось на зразок сотень ВПД / секунду.

Підсумок: є випадки, коли обробка винятків накладних витрат може бути суттєвою, але це майже напевно не один із них.

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