Myślę, że @JackAidley powiedział już o tym , ale pozwólcie, że sformułuję to w następujący sposób:
bez wyjątków (np. C)
W zwykłym przepływie kodu masz:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
W przypadku „wczesnego błędu” kod nagle wyświetla:
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
Jeśli zauważysz ten wzorzec - return
w bloku else
(a nawet if
), przerób go natychmiast, aby kod nie zawierał else
bloku:
/* only code like this at University, to please structured programming professors */
function foo {
if (condition) {
lots_of_statements;
}
return;
}
W prawdziwym świecie…
/* code like this instead */
if (!condition) {
error_handling;
return;
}
lots_of_statements;
Pozwala to uniknąć zbyt głębokiego zagnieżdżenia i spełnia warunek „wczesnego wybicia” (pomaga utrzymać umysł - i przepływ kodu - w czystości) i nie narusza „wstawienia bardziej prawdopodobnej rzeczy do if
elementu”, ponieważ po prostu nie ma else
części .
C
i porządki
Zainspirowany odpowiedzią na podobne pytanie (które popełniło błąd), oto sposób czyszczenia w C. Możesz tam użyć jednego lub dwóch punktów wyjścia, tutaj jest jeden dla dwóch punktów wyjścia:
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);
}
Możesz zwinąć je w jednym punkcie wyjścia, jeśli jest mniej do zrobienia:
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);
}
Takie użycie goto
jest w porządku, jeśli sobie z tym poradzisz; rada, aby nie używać, goto
jest skierowana do osób, które nie mogą jeszcze samodzielnie zdecydować, czy użycie jest dobre, dopuszczalne, złe, kod spaghetti, czy coś innego.
Wyjątki
Powyższe mówi o językach bez wyjątków, które bardzo wolę siebie (mogę użyć jawnej obsługi błędów znacznie lepiej i ze znacznie mniejszym zaskoczeniem). Aby zacytować igli:
<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 ;)
Ale oto sugestia, jak to zrobić dobrze w języku z wyjątkami i kiedy chcesz je dobrze wykorzystać:
błąd powrotu w obliczu wyjątków
Możesz zastąpić większość wczesnych return
s rzucając wyjątek. Jednakże , twój normalny przepływ programu, czyli dowolnego strumienia kodu, w którym program nie napotka, dobrze, wyjątek ... stan błędu lub somesuch, nie powinna podnosić żadnych wyjątków.
To znaczy że…
# 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?"
… Jest w porządku, ale…
/* do not code like this! */
try {
openFile(xyz, "rw");
} catch (LockedException e) {
return "file is locked";
}
closeFile(xyz);
return "file is not locked";
… nie jest. Zasadniczo wyjątek nie jest elementem kontroli . To sprawia, że Operacje wyglądają na ciebie dziwnie („ci programiści Java ™ zawsze mówią nam, że te wyjątki są normalne”) i mogą utrudniać debugowanie (np. Powiedzieć IDE, aby po prostu złamało dowolny wyjątek). Wyjątki często wymagają środowiska wykonawczego, aby rozwinąć stos w celu wygenerowania śledzenia itp. Prawdopodobnie jest więcej powodów.
Sprowadza się to do: w języku wspierającym wyjątki, używaj tego, co pasuje do istniejącej logiki i stylu i wydaje się naturalne. Jeśli piszesz coś od zera, uzgodnij to wcześniej. Pisząc bibliotekę od podstaw, pomyśl o swoich konsumentach. (Nigdy nie używaj abort()
w bibliotece…) Ale cokolwiek zrobisz, nie z reguły rzucaj wyjątek, jeśli operacja będzie kontynuowana (mniej więcej) normalnie po nim.
ogólne porady wrt. Wyjątki
Postaraj się najpierw wykorzystać wszystkie wyjątki w programie uzgodnione przez cały zespół programistów. Zasadniczo je zaplanuj. Nie używaj ich w obfitości. Czasami nawet w C ++, Java ™, Python powrót błędu jest lepszy. Czasami tak nie jest; używaj ich z myślą.