Я думаю, что @JackAidley уже сказал суть этого , но позвольте мне сформулировать это так:
без исключений (например, C)
В обычном потоке кода у вас есть:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
В случае с ошибкой раньше, ваш код внезапно читает:
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
Если вы обнаружите этот шаблон - return
в else
(или даже if
) блоке, немедленно переделайте его, чтобы у рассматриваемого кода не было else
блока:
/* only code like this at University, to please structured programming professors */
function foo {
if (condition) {
lots_of_statements;
}
return;
}
В реальном мире…
/* code like this instead */
if (!condition) {
error_handling;
return;
}
lots_of_statements;
Это позволяет избежать слишком глубокого вложения и выполняет случай «вырваться раньше» (помогает сохранить ум - и поток кода - чистым) и не нарушает «положить более вероятную вещь в if
часть», потому что просто нет else
части ,
C
и очистка
Вдохновленный ответом на аналогичный вопрос (который получил это неправильно), вот как вы делаете очистку с C. Вы можете использовать одну или две точки выхода, вот одна для двух точек выхода:
struct foo *
alloc_and_init(size_t arg1, int arg2)
{
struct foo *res;
if (!(res = calloc(sizeof(struct foo), 1)))
return (NULL);
if (foo_init1(res, arg1))
goto err;
res.arg1_inited = true;
if (foo_init2(&(res->blah), arg2))
goto err;
foo_init_complete(res);
return (res);
err:
/* safe because we use calloc and false == 0 */
if (res.arg1_inited)
foo_dispose1(res);
free(res);
return (NULL);
}
Вы можете свернуть их в одну точку выхода, если нужно сделать меньше очистки:
char *
NULL_safe_strdup(const char *arg)
{
char *res = NULL;
if (arg == NULL)
goto out;
/* imagine more lines here */
res = strdup(arg);
out:
return (res);
}
Это использование goto
прекрасно, если вы можете справиться с этим; Совет по отказу от использования goto
адресован людям, которые еще не могут самостоятельно решить, является ли использование хорошим, приемлемым, плохим, кодом спагетти или чем-то еще.
Исключения
Вышесказанное говорит о языках без исключений, которые я предпочитаю сам (я могу использовать явную обработку ошибок гораздо лучше и с гораздо меньшим удивлением). Процитирую Игли:
<igli> exceptions: a truly awful implementation of quite a nice idea.
<igli> just about the worst way you could do something like that, afaic.
<igli> it's like anti-design.
<mirabilos> that too… may I quote you on that?
<igli> sure, tho i doubt anyone will listen ;)
Но вот предложение, как вы делаете это хорошо на языке с исключениями, и когда вы хотите использовать их хорошо:
возврат ошибки в случае исключений
Вы можете заменить большинство ранних return
символов на исключение. Однако ваш обычный программный поток, т. Е. Любой поток кода, в котором программа не встретила, ну, исключение ... условие ошибки или что-то подобное, не должен вызывать никаких исключений.
Это значит, что…
# this page is only available to logged-in users
if not isLoggedIn():
# this is Python 2.5 style; insert your favourite raise/throw here
raise "eh?"
... хорошо, но ...
/* do not code like this! */
try {
openFile(xyz, "rw");
} catch (LockedException e) {
return "file is locked";
}
closeFile(xyz);
return "file is not locked";
… не является. По сути, исключение не является элементом потока управления . Это также заставляет Операции выглядеть странно на вас («эти Java-программисты всегда говорят нам, что эти исключения являются нормальными») и может препятствовать отладке (например, сказать IDE, что нужно просто сломать любое исключение). Исключения часто требуют, чтобы среда выполнения разматывала стек для получения трассировок и т. Д. Вероятно, есть и другие причины против этого.
Это сводится к следующему: на языке, поддерживающем исключения, используйте все, что соответствует существующей логике и стилю и выглядит естественным. Если вы пишете что-то с нуля, договоритесь об этом заранее. Если вы пишете библиотеку с нуля, подумайте о ваших потребителях. (Никогда не используйте abort()
в библиотеке также…) Но что бы вы ни делали, не, как правило, выдается исключение, если операция продолжается (более или менее) нормально после нее.
общий совет относительно Исключения
Постарайтесь сначала использовать все исключения в программе, согласованные всей командой разработчиков. В основном, планируйте их. Не используйте их в изобилии. Иногда даже в C ++, Java ™, Python возврат ошибок лучше. Иногда это не так; используйте их с мыслью.