Я подумав над цим і не міг придумати приклад. Чому хтось хотів би зловити виняток і нічого не робити з цим? Чи можете ви навести приклад? Можливо, це просто щось, чого ніколи не слід робити.
Я подумав над цим і не міг придумати приклад. Чому хтось хотів би зловити виняток і нічого не робити з цим? Чи можете ви навести приклад? Можливо, це просто щось, чого ніколи не слід робити.
Відповіді:
Я роблю це постійно з такими речами, як помилки конверсії в D:
import std.conv, std.stdio, std.exception;
void main(string[] args) {
enforce(args.length > 1, "Usage: foo.exe filename");
double[] nums;
// Process a text file with one number per line into an array of doubles,
// ignoring any malformed lines.
foreach(line; File(args[1]).byLine()) {
try {
nums ~= to!double(line);
} catch(ConvError) {
// Ignore malformed lines.
}
}
// Do stuff with nums.
}
З цього приводу я думаю, що всі блоки уловки повинні мати щось у них, навіть якщо це щось лише коментар, що пояснює, чому ви ігноруєте виняток.
Редагувати: Я також хочу наголосити, що, якщо ви збираєтесь робити щось подібне, ви повинні бути обережними лише для того, щоб зловити лише той конкретний виняток, який ви хочете ігнорувати. Робити звичайну стару catch {}
майже завжди погано.
Один із прикладів, коли я думаю, що це нормально, щоб просто проковтнути виняток, не роблячи нічого, навіть реєструючи виняток, - це сам код реєстрації.
Якщо ви спробували щось зареєструвати і отримали виняток, ви не можете багато з цим зробити:
Це залишає перед вами варіант «найменшого зла» - тихо ковтати його, дозволяючи додатку продовжувати виконувати свою основну роботу, але загрожує можливістю усунення несправностей.
Якщо виняток буде викинуто операцією, яка все-таки була необов'язковою, то нічого робити не може. Можливо, це не буде корисно для цього. У такому випадку ви можете просто захотіти його зловити і нічого не робити.
Якщо ви це робите, додайте коментар. Завжди коментуйте все, що схоже на помилку (провал у switch
виписці, порожній catch
блок, присвоєння умові).
Ви можете стверджувати, що це не належне використання винятків, але це вже інше питання.
Порожні catch
блоки є запахом коду на більшості мов. Основна ідея - використовувати винятки для виняткових ситуацій, а не використовувати їх для логічного контролю. Усі винятки треба десь обробляти.
Як наслідок цього підходу, коли ви програмуєте один конкретний рівень програми, у вас є кілька варіантів:
Це насправді не залишає місця для порожніх catch
блоків.
ВИДАЛЕНО ДО ДОДАТИ : припустимо, ви програмуєте мовою, де викидання виключень - це звичайний спосіб контролювати логіку програми (одна з альтернатив goto
). Тоді порожній catch
блок у програмі, написаній цією мовою, дуже схожий на порожній else
блок традиційною мовою (або зовсім не else
блокуючий). Однак я вважаю, що це не стиль програмування, рекомендований спільнотами C #, Java або C ++.
У деяких випадках Java вимагає, щоб ви обробляли виняток, який, за абсолютно жодних обставин, ніколи не може відбутися. Розглянемо цей код:
try {
bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}
Кожна реалізація платформи Java необхідна для підтримки наступних стандартних діаграм.
...
UTF-8
Не порушуючи вашу платформу Java, просто не існує способу викликати цей виняток. Так навіщо турбуватись з цим? Але ви не можете просто пропустити статтю про випробування.
throw new Error(e)
просто, щоб бути абсолютно впевненим, що я нічого не пропустив (або повідомив про справді розбиту платформу).
Як правило, ні. Ви або хочете викинути виняток у стек, або записувати те, що сталося.
Однак я часто це роблю, коли я розбираю рядки і перетворюю на числа (особливо в проектах зі створення карти, які користуються одноразово та викидають різноманітність).
boolean isNonZeroNumber = false;
try {
if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
b = true;
}
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}
return b;
У деяких випадках виняток зовсім не є винятковим; насправді це очікується. Розглянемо цей приклад:
/* Check if the process is still alive; exitValue() throws an exception if it is */
try {
p.exitValue();
processPool.remove(p);
}
catch (IllegalThreadStateException e) { /* expected behaviour */ }
Оскільки в java.lang.Process () немає методу isAlive (), про єдиний спосіб перевірити, чи він ще живий, є виклик exitValue (), який викидає IllegalThreadStateException, якщо процес все ще працює.
З мого скромного досвіду, рідко це добре. Ти пробіг може змінюватися, хоча.
Майже кожен раз, коли я бачив це в нашій кодовій базі, це було тому, що я відслідковував помилку, яку з'їв виняток. Інакше кажучи, не надаючи жодного коду, програма не може вказувати на помилку чи виконувати іншу дію.
Іноді, наприклад, на шарах API, ви, можливо, не хочете або не можете залишити винятки минулими, тому в такому випадку я схильний намагатися спіймати найбільш загальні, а потім записувати їх. Ще раз, щоб принаймні дати шанс сеансу налагодження / діагностики.
Як правило, якщо воно повинно бути порожнім, найменше, що я роблю, - це якесь твердження, тому принаймні щось відбувається під час сеансу налагодження. Однак, якщо я не можу впоратися з цим, я схильний їх повністю опустити.
IMO є одне місце, де порожні заяви про вилов. У тестових випадках, коли ви очікуєте винятку:
try
{
DoSomething(); //This should throw exception if everything works well
Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
//Expected to get here
}
Я вважаю, що є певні випадки, коли виправдано застереження про порожній вилов - це випадки, коли потрібно, щоб код просто продовжував роботу, якщо певна операція не вдалася. Однак я думаю, що цей шаблон можна легко використати, тому кожне використання слід ретельно вивчити, щоб переконатися, що немає кращого способу впоратися з ним. Зокрема, цього ніколи не слід робити, якщо він залишає програму в непослідовному стані або якщо це може призвести до відмови якоїсь іншої частини коду.
Я не вірю в те, що не має певного рівня оповіщення, коли відбувається виняток - чи не слід однією з цілей програмування покращити код? Якщо виняток трапляється 10% часу, і ви ніколи про це не знаєте, то виняток завжди буде таким поганим, або гіршим.
Однак я бачу іншу сторону, що якщо виняток не приносить реальної шкоди при обробці коду, то навіщо піддавати цього користувача. Як правило, я реалізую рішення - це його реєстрація моїм класом реєстраторів (тобто в кожному класі, який я коли-небудь пишу на роботі).
Якщо це доброякісне виняток, то я телефоную на метод .Debug () мого Logger; інакше Logger.Error () (і (можливо) кинути).
try
{
doWork();
}
catch(BenignException x)
{
_log.Debug("Error doing work: " + x.Message);
}
До речі, в моїй реалізації мого реєстратора здійснення дзвінка до методу .Debug () буде реєструвати його лише в тому випадку, якщо я в файлі App.Config вказав, що рівень журналу виконання програми знаходиться в режимі налагодження.
Перевірка наявності є гарним випадком використання:
// If an exception happens, it doesn't matter. Log the initial value or the new value
function logId(person) {
let id = 'No ID';
try {
id = person.data.id;
} catch {}
console.log(id);
}
Інший випадок, коли використовується finally
пункт:
function getter(obj){}
function objChecker()
{
try
{
/* Check argument length and constructor type */
if (getter.length === 1 && getter.constructor === Function)
{
console.log("Correct implementation");
return true;
}
else
{
console.log("Wrong implementation");
return false;
}
}
catch(e)
{
}
finally
{
console.log(JSON.stringify(getter))
}
}
// Test the override of the getter method
getter = getter;
objChecker();
getter = [];
objChecker();
getter = {};
objChecker();
getter = RegExp;
objChecker();
getter = Function;
objChecker();
Існує пропозиція дозволити пропущення обов'язкового вилову в ECMAScript, що стосується цього та подібних випадків використання.
Список літератури
Єдиний раз, коли мені справді потрібно було зробити щось подібне, це був клас реєстрації для консольного додатка. Був глобальний обробник лову верхнього рівня, який видав помилку STDOUT, записав помилку у файл, а потім закрив програму кодом помилки> 0.
Проблема тут полягала в тому, що іноді вхід у файл не вдався. Дозволи до каталогу не дозволяють вам писати файл, файл був виключно заблокований, як би там не було. Якщо це сталося, я не міг обробляти виняток так само, як у мене в іншому місці (ловити, записувати відповідні реквізити , загортати в кращий тип винятків тощо), оскільки реєстрація даних про винятки призвела до того, що реєстратор пройшов ті ж дії ( намагається записати у файл), який вже не вдався. Коли вони знову зазнали невдачі ... Ви бачите, куди я йду. Він потрапляє в нескінченну петлю.
Якщо ви скасуєте кілька блоків спробу {}, ви можете виключати те, що відображається у вікні повідомлень (не те, що потрібно для програми беззвучного налаштування). Тож у тому методі, який записує у файл журналу, у мене порожній обробник лову. Це не приховує помилку, оскільки ви все одно отримуєте код помилки> 0, він просто зупиняє нескінченний цикл і дозволяє програмі вишукано вийти.
Там, звичайно, є коментар, який пояснює, чому це порожньо.
(Я збирався опублікувати це раніше, я просто боявся потрапити у небуття. Оскільки я не єдиний, хоча ...)
Це нормально в ситуації, коли якась послідовність повинна бути виконана незалежно від того, що з найважливішим фрагментом розміщено в кінці.
Наприклад. У русі управління передається зв'язок хоста з контролером. В надзвичайних ситуаціях є ряд підготовчих кроків до припинення руху, зупинки генерації траєкторії, уповільнення двигунів, включення перерв, відключення підсилювача і після цього потрібно вбити живлення шини. Все повинно відбуватися послідовно, і якщо один з кроків не вдається, решту кроків необхідно виконати, навіть з прийнятим ризиком пошкодження обладнання. Скажіть, навіть якщо все вище не вдасться, потужність шини вбити все одно має відбутися.
Вимкнення системних ресурсів витончено, щоб відновитись після помилки
Наприклад. Якщо ви використовуєте службу в фоновому режимі , що не забезпечує зворотний зв'язок з користувачем, ви не можете натиснути індикацію помилки для користувача , але вам дійсно потрібно , щоб закрити ресурси використовуються в витонченої манері.
try
{
// execution code here
}
catch(Exception e)
{
// do nothing here
}
finally
{
// close db connection
// close file io resource
// close memory stream
// etc...
}
В ідеалі, ви б використовували ловлю в режимі налагодження, щоб ловити помилки та друкувати їх на консолі або в файл журналу для тестування. В виробничому середовищі фонові послуги, як правило, очікують, що вони не перебиватимуть користувача, коли буде видалена помилка, тому вихід помилок повинен бути придушений.