Napisałem funkcję, która prosi użytkownika o wprowadzenie danych, dopóki użytkownik nie wprowadzi dodatniej liczby całkowitej (liczby naturalnej). Ktoś powiedział, że nie powinienem wyrzucać i wychwytywać wyjątków w mojej funkcji i pozwolić, aby wywołujący moją funkcję je obsługiwał.
Zastanawiam się, co sądzą o tym inni programiści. Prawdopodobnie niewłaściwie wykorzystuję wyjątki w funkcji. Oto kod w Javie:
private static int sideInput()
{
int side = 0;
String input;
Scanner scanner = new Scanner(System.in);
do {
System.out.print("Side length: ");
input = scanner.nextLine();
try {
side = Integer.parseInt(input);
if (side <= 0) {
// probably a misuse of exceptions
throw new NumberFormatException();
}
}
catch (NumberFormatException numFormExc) {
System.out.println("Invalid input. Enter a natural number.");
}
} while (side <= 0);
return side;
}
Interesują mnie dwie rzeczy:
- Czy powinienem pozwolić rozmówcy martwić się o wyjątki? Istotą tej funkcji jest to, że dręczy użytkownika, dopóki użytkownik nie wprowadzi liczby naturalnej. Czy punkt funkcji jest zły? Nie mówię o interfejsie użytkownika (użytkownik nie jest w stanie wydostać się z pętli bez odpowiedniego wejścia), ale o zapętlonym wejściu z obsługiwanymi wyjątkami.
- Czy powiedziałbyś, że instrukcja throw (w tym przypadku) jest niewłaściwym wykorzystaniem wyjątków? Mogę łatwo utworzyć flagę do sprawdzania poprawności numeru i wypisać komunikat ostrzegawczy na podstawie tej flagi. Ale to dodałoby więcej linii do kodu i myślę, że jest on w pełni czytelny.
Rzecz w tym, że często piszę osobną funkcję wejściową. Jeśli użytkownik musi wprowadzić liczbę wiele razy, tworzę osobną funkcję wprowadzania, która obsługuje wszystkie wyjątki i ograniczenia formatowania.
exceptions
usr
źródło
źródło
Odpowiedzi:
Wyjątkiem jest to, że pozwala metodzie powiedzieć dzwoniącemu, który wszedł w stan, w którym nie mógł normalnie kontynuować, bez zmuszania użytkownika do osadzenia kodu błędu w wartości zwracanej.
W twoim przypadku twoja metoda dokładnie wie, co robić, gdy wartość wejściowa nie jest większa niż 0. Jedynym powodem, dla którego zapisujesz tutaj wiersze, jest to, że zdarza się, że generujesz ten sam wyjątek, jaki byś otrzymał, gdyby dane wejściowe nie były liczbą. Jednak wyjątek, który zgłaszasz, nie pokazuje poprawnie, dlaczego twój kod nie lubi danych wejściowych. Gdyby ktoś inny przyszedł i zobaczył ten kod, musiałby poświęcić dodatkowy czas na sprawdzenie, jak dokładnie działa.
źródło
To złe użycie wyjątków. Na początek liczba dodatnia nie jest wyjątkiem formatu.
Po co w ogóle korzystać z wyjątków? Jeśli wiesz, które dane wejściowe są niedozwolone, po prostu nie wychodź z pętli, dopóki nie uzyskasz prawidłowych danych wejściowych od użytkownika, coś takiego:
źródło
Integer.parseInt()
zgłasza a,NumberFormatException
jeśli nie może przeanalizować podanego argumentu ciągu. Nie ma potrzeby, abyś sam (i nie będziesz w stanie) sam zgłosić wyjątku.Integer.parseInt()
metoda rzuci za ciebie wyjątek, jeśli wystąpi, nie będziesz mógł go później wyrzucić, ponieważ został już wyrzucony.Łap wyjątki tylko wtedy, gdy zamierzasz zrobić coś, co jest istotne dla bieżącego wywołania metody; tj. czyszczenie, logika awarii itp. W tym przypadku catch po prostu wysyła komunikat do konsoli, nie ma znaczenia dla metody sideInput, dlatego może być obsługiwany dalej w łańcuchu połączeń / stosie.
Tutaj możesz pozbyć się try / catch i po prostu udokumentować wywołanie metody:
Nadal trzeba poradzić sobie z tym wyjątkiem w łańcuchu połączeń / stosie!
źródło
Nie powinieneś rzucać i wychwytywać tego samego wyjątku w metodzie, nawet myślę, że blok przechwytuje ten sam wyjątek, który rzucasz, więc tak naprawdę go nie rzucasz.
Jeśli się
parseInt
udało, to nie jestNumberFormatException
.jeśli strona jest mniejsza niż zero, powinieneś rzucić
NegativeSideLengthException
;Utwórz niestandardowy / biznesowy wyjątek o nazwie
NegativeSideLengthException
Następnie
sideInput
zgłasza NegativeSideLengthExceptionMożesz nawet (jeśli chcesz) dodać kolejny blok przechwytywania, aby złapać
NegativeSideLengthException
i nie ma metody rzucić go.Flagi nie są dobrym sposobem radzenia sobie z wyjątkami.
źródło
Wyjątki to koszmarne rzeczy, przynoszą więcej złożoności niż rozwiązują.
Po pierwsze, jeśli nie złapiesz wyjątków, dzwoniący może tylko to zrobić
on error resume next
, to znaczy po tygodniu nawet ty nie będziesz wiedział, co twoja funkcja może rzucić i co z tym zrobić:Zasadniczo, jeśli je złapiesz, musisz bardzo dobrze rozumieć umowy i gwarancje wyjątków. To rzadko zdarza się w prawdziwym świecie. A także twój kod będzie trudny do odczytania.
Zabawne jest również to, że jeśli naprawdę masz szansę poradzić sobie z wyjątkami, potrzebujesz prawdziwego języka RAII, co jest dość zabawne, ponieważ Java i .NET to wyjątki ...
Powtarzam to jeszcze raz, ale ...:
http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx
http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx
http://www.joelonsoftware.com/items/2003/10/13.html
źródło
: throw(thisexception, thatexception)
są wręcz błędne i nigdy nie powinny być używane, ponieważ w przeciwnym razie dostaniesz nieoczekiwany wyjątek.catch
. Podczas gdy zignorowana wartość zwracana jest niemożliwa do przeszukania - można ją zidentyfikować tylko poprzez przegląd kodu po linii. Na koniec, konstruktory nie mają wartości zwracanych, jest to główny powód do stosowania wyjątków.