2012-12-23 12 views
15

Mam pewne problemy ze zrozumieniem różnic między wyjątkami w języku Java w wersjach checked i unchecked.Sprawdzone i niezaznaczone wyjątki w Javie

  1. Po pierwsze, wyjątki od checked powinny wyglądać na anomalie podczas kompilacji. Przykłady przedstawione w różnych źródłach cytować łączność z bazami danych, obsługę plików, ponieważ niektóre z nich, podczas gdy unchecked wyjątki mają szukać błędów na części programisty, jak indeksowanie poza zakres tablicy itd

nie powinno to jest na odwrót? Mam na myśli, że łączność z bazami danych odbywa się podczas pracy, prawda? To samo dotyczy obsługi plików. Nie otwierasz uchwytu pliku podczas kompilacji, więc dlaczego pojawia się potencjalny błąd podczas kompilacji? Z drugiej strony, indeksowanie tablicy poza jej zakresem jest już wykonywane w programie, co można sprawdzić podczas kompilacji (jeśli nieprawidłowy indeks jest dostarczany przez użytkownika podczas działania, to jest w porządku, aby był to czas wykonywania problem). Czego tu mi brakuje?

2 Po drugie, jak może RunTimeException, sama będąc unchecked, podklasa Exception, która jest checked? Co to oznacza?

Znalazłem przykład w książce Herberta Schildt objaśniający użycie checked wyjątkami:

class ThrowsDemo { 
    public static char prompt(String str) 
     throws java.io.IOException { 
    System.out.print(str + ": "); 
    return (char) System.in.read(); 
    } 
    public static void main(String args[]) { 
    char ch; 
    try { 
     ch = prompt("Enter a letter"); 
    } 
    catch(java.io.IOException exc) { 
    System.out.println("I/O exception occurred."); 
    ch = 'X'; 
    } 
    System.out.println("You pressed " + ch); 
    } 
} 

jest klauzula throws konieczne tutaj? Dlaczego nie mogę zrobić, to po prostu normalnie z try-catch oświadczeniu tak (przepraszam nie wiem jak symulować IO Exception, więc nie mogliśmy sprawdzić to sam!):

class ThrowsDemo { 
    public static char prompt(String str) { 
    System.out.print(str + ": "); 
    return (char) System.in.read(); 
    } 
    public static void main(String args[]) { 
    char ch; 
    try { 
     ch = prompt("Enter a letter"); 
    } 
    catch(java.io.IOException exc) { 
    System.out.println("I/O exception occurred."); 
    ch = 'X'; 
    } 
    System.out.println("You pressed " + ch); 
    } 
} 
+0

Możliwe duplikat [Różnica pomiędzy Nierejestrowanego wyjątku lub wyjątkiem wykonawczego] (http://stackoverflow.com/questions/2699580/difference-between-unchecked-exception-or-runtime-exception) – Tom

+0

sprawdzone wyjątki * nie * w celu wykrycia problemów podczas kompilacji. Taki jest cel błędów kompilatora. – erickson

Odpowiedz

21

Wywoływany wyjątek CheckedException musi zostać obsłużony przez wywołującego, Niezaznaczony wyjątek nie.

Podczas projektowania aplikacji należy wziąć pod uwagę wyjątkową sytuację, którą zarządzasz.

Na przykład, jeśli zaprojektujesz metodę sprawdzania poprawności, która sprawdza poprawność niektórych danych wprowadzonych przez użytkownika, to wiesz, że wywołujący musi sprawdzić wyjątek sprawdzania poprawności i wyświetlać błędy użytkownikowi w ładny sposób. Powinien to być sprawdzony wyjątek.

Dla tych wyjątkowych warunków, które można odzyskać: wyobraź sobie, że masz moduł równoważenia obciążenia i chcesz powiadomić osobę dzwoniącą, że jeden z serwerów "n" jest wyłączony, więc osoba dzwoniąca musi odzyskać informacje o zdarzeniu, przekierowując wiadomość na inny serwer; Powinien to być sprawdzony wyjątek, ponieważ ważne jest, aby wywołujący (klient) próbował odzyskać błąd i nie pozwolił, by błąd przerwał przepływ programu.

Zamiast tego jest wiele warunków, które nie powinny się zdarzyć i/lub powinny one przerwać program. Na przykład błąd programowania (np. Dzielenie przez zero, wyjątek wskaźnika zerowego), nieprawidłowe użycie interfejsu API (IllegalStateException, OperationNotSupportedException), awaria sprzętu lub po prostu niewielka sytuacja, której nie można odzyskać (utracone połączenie z serwerem), albo dzień zagłady :-); w takich przypadkach normalne postępowanie polega na umożliwieniu wyjątkowi dotarcia do najbardziej zewnętrznego bloku kodu, który wyświetla użytkownikowi nieprzewidziany błąd, a aplikacja nie może nic zrobić, aby kontynuować. Jest to stan krytyczny, więc jedyną rzeczą, którą możesz zrobić, jest wydrukowanie go do dzienników lub wyświetlenie go użytkownikowi w interfejsie użytkownika. W takich przypadkach uchwycenie wyjątku jest błędne, ponieważ po wychwyceniu wyjątku należy ręcznie zatrzymać program, aby uniknąć dalszych szkód; więc może być lepiej pozwolić na wyjątek "hit fan" :)

Z tych powodów istnieją wyjątki, które nie są zaznaczone również w JRE: OutOfMemoryError (nieodwracalne), NullPointerException (to błąd, który musi być naprawione), ArrayIndexOutOfBoundsException (inny przykład błędu) i tak dalej.

Osobiście uważam, że również wyjątek SQLException powinien zostać odznaczony, ponieważ oznacza błąd w programie lub problem z połączeniem z bazą danych. Ale jest wiele przykładów, w których otrzymujesz wyjątek, że naprawdę nie masz pojęcia, jak zarządzać (RemoteException).

Najlepszym sposobem na obsługę wyjątków jest: jeśli możesz odzyskać wyjątek lub nim zarządzać, obsłuż go. W przeciwnym razie wyjdzie wyjątek; ktoś inny będzie musiał sobie z tym poradzić. Jeśli jesteś ostatnim "kimś innym" i nie wiesz, jak sobie poradzić z wyjątkiem, po prostu go wyświetl (log lub wyświetl w interfejsie użytkownika).

+0

Cool. Tylko kilka pytań, jeśli wystąpi nieodwracalny błąd, JVM i tak je zakończy. Jaki jest sens podniesienia wyjątku w czasie wykonywania? Tylko w celu nadania odpowiedniego komunikatu o stanie? Miałem wrażenie, że wyjątki pozwalają złapać pułapkę błędu, wykonać pewne prace czyszczące i pozwolić programowi normalnie powrócić do normalnego stanu.A po drugie, jak możesz "odzyskać" z zaznaczonego wyjątku? Co dokładnie masz na myśli przez "odzyskać"? – SexyBeast

+2

Niezupełnie. W razie awarii systemu plików maszyna wirtualna JVM może nadal działać. Myślę, że również w przypadku wystąpienia OutOfMemoryError, JVM nie zatrzymuje się: istnieją wątki, które nie wymagają dodatkowej pamięci, aby można je było kontynuować, lub niektóre odniesienia mogą zostać później uwolnione, a program nadal może działać poprawnie. Podniesienie Wyjątku w czasie wykonywania oznacza powiedzenie "ten wyjątek, zazwyczaj nie masz/nie możesz tego zrobić, ale jeśli chcesz, możesz poczuć się wolnym". Na przykład, jeśli mam zaprojektowany specjalny komputer, który jest w stanie zamontować nowe układy pamięci RAM na komputerach, mogę również obsłużyć wyjątek OutOfMemoryException! :) –

+0

Przez "odzyskać" rozumiem taki scenariusz: wywołuje się metodę, która wysyła pewien komunikat do zdalnego komputera przez gniazdo. Jeśli połączenie zostanie chwilowo przerwane, mogę ponownie spróbować ponownie kilka razy, aby się poddać. Decyzja o tym, czy użytkownik powinien spróbować ponownie ręcznie, czy zaimplementować tę logikę "odzyskiwania" w oprogramowaniu, należy do użytkownika. Jeśli masz do czynienia z użytkownikiem, który może spróbować ręcznie, zasady "nieodzyskujące" są prawdopodobnie najlepsze. Ale jeśli wdrażasz serwer działający bez interakcji użytkownika, musisz pomyśleć, czy to jest w przypadku odzyskiwania tymczasowych awarii sieci. –

8
  1. ty nie trzeba zadeklarować niezaznaczone wyjątki w klauzuli throws; ale musisz musi deklarować sprawdzone wyjątki;
  2. RuntimeException i i wszystkie ich podklasy (IllegalArgumentException, StackOverflowError itd.) Są nieobmianymi wyjątkami; fakt, że RuntimeException nie jest zaznaczony, w przeciwieństwie do innych podklas Throwable, jest zgodny z projektem;
  3. nie ma czegoś takiego jak "wyjątki czasu kompilacji".

Przyjmuje się, że niezaznaczone wyjątki są zgłaszane w przypadku błędów JVM lub błędów programisty. Jednym znanym takim wyjątkiem jest NullPointerException, często określany skrótem NPE, który jest podklasą RuntimeException, a zatem niezaznaczony.

Inną bardzo istotną różnicą między niezaznaczonymi wyjątkami a sprawdzonymi wyjątkami jest to, że w bloku try-catch, jeśli chcesz uchwycić niezaznaczone wyjątki, musisz je wyraźnie złapać:.

Ostatnia uwaga: jeśli masz klasy wyjątków E1 i E2 i E2 rozciąga E1, potem wzrok i/lub rzucania E1 również łapie/rzuca E2. To oznacza sprawdzane i niezaznaczone wyjątki.Ma to wpływ na bloki catch: jeśli rozróżnisz między złapaniem E2 a E1, musisz najpierw złapać E2.

Na przykład:

// IllegalArgumentException is unchecked, no need to declare it 
public void illegal() 
{ 
    throw new IllegalArgumentException("meh"); 
} 

// IOException is a checked exception, it must be declared 
public void ioerror() 
    throws IOException 
{ 
    throw new IOException("meh"); 
} 

// Sample code using illegal(): if you want to catch IllegalArgumentException, 
// you must do so explicitly. Not catching it is not considered an error 
public void f() 
{ 
    try { 
     illegal(); 
    } catch (IllegalArgumentException e) { // Explicit catch! 
     doSomething(); 
    } 
} 

Mam nadzieję, że to sprawia, że ​​rzeczy jaśniej ...

2

Kompilator sprawia tylko pewien sposób nie może rzucać sprawdzonej wyjątek, jeśli nie objawi. Powszechnie uważa się, że takie sprawdzanie przez kompilator powinno być wykonywane dla wyjątków, których wystąpienie jest poza kontrolą programisty, takich jak przykłady, które cytujesz (łączność z bazą danych, brakujące pliki itp.). Niezaznaczone wyjątki "nie powinny się zdarzać", więc kompilator nie wymusza na nich deklaracji.

chodzi o symulowanie IOException lub każdy inny, to jest trywialne:

throw new IOException(); 

W przykładzie metoda prompt może rzucić IOException, dlatego musi go zgłosić. Nie ma to nic wspólnego z tym, jak radzisz sobie z wyjątkiem w punkcie, w którym nazywasz tę metodę.

RuntimeException jest podklasą Exception, aby ułatwić wychwycenie wszystkich wyjątków za pomocą klauzuli catch Exception. Mogło to zostać zaprojektowane inaczej; Hierarchia klas wyjątków Java to bałagan.

+0

Obsługa plików lub połączenie z bazą danych odbywa się w czasie wykonywania, w jaki sposób można je sprawdzić podczas kompilacji? – SexyBeast

+0

Kompilator zapewnia tylko, że metoda nie może wyrzucić sprawdzonego wyjątku, jeśli nie zadeklarowała go. –

0

jeśli nie umieścić klauzulę rzuca tu wtedy ten błąd będzie występować

ThrowsDemo.java:5: nieudokumentowanych wyjątek java.io.IOException; musi zostać złapany lub d eclared zostać wyrzucony return (char) System.in.read();

, więc wyrzuca klauzulę w razie potrzeby.

5
  1. Nie. Wszystkie wyjątki występują w czasie wykonywania. Sprawdzane wyjątki są wyjątkami, które zmuszają rozmówcę do obsługi lub deklarowania. Zwykle są one przeznaczone do sygnalizowania zwrotów błędów, które nie są spowodowane przez błąd programisty (np. Brak pliku lub problem z połączeniem sieciowym). Wyjątki w czasie wykonywania mają na ogół sygnalizować nieodwracalne błędy. Nie zmuszają osoby dzwoniącej do obsługi lub zadeklarowania ich. I wiele z nich rzeczywiście sygnalizuje błędy programowania (takie jak NullPointerException).

  2. Ponieważ w ten sposób JLS definiuje niesprawdzony wyjątek: wyjątek, który jest lub rozszerza RuntimeException, co samo rozszerza wyjątek. Użycie pojedynczego katalogu głównego dziedziczenia pozwala na obsługę wszystkich możliwych wyjątków w klauzuli catch.

chodzi swój przykład: tak, rzuca klauzula jest obowiązkowa, ponieważ IOException jest sprawdzana wyjątek i że kod wewnątrz metody jest podatny rzucić jeden.

+0

Nie rozumiem, w jaki sposób można sprawdzić poprawność uchwytu pliku podczas kompilacji? I dlaczego nie mogę tego zrobić za pomocą zwykłej instrukcji 'try-catch'? Co osiąga tu "throws", których 'try-catch' nie może? – SexyBeast

+1

Wszystkie wyjątki występują w czasie wykonywania. To są pierwsze słowa z mojej odpowiedzi. Nie ma wyjątku podczas kompilacji. To nie istnieje. 'throws' sygnalizuje, że metoda może wygenerować wyjątek po wywołaniu. 'try/catch' przechwytuje wyjątek wywoływany przez wywoływaną metodę. 'throws' jest jak panel" Niebezpieczne! śliskie podłoże ". "try/catch" jest jak "Wow, ziemia jest śliska, ja się tym zajmę". –

+0

Dlaczego więc nie mogę zawsze używać 'try-catch' zamiast' throws'? – SexyBeast

0

Sprawdzone i niesprawdzonych wyjątki

Istnieją dwa rodzaje wyjątków: sprawdzone wyjątki i niezaznaczone wyjątki. Główna różnica między sprawdzonym i niezaznaczonym wyjątkiem polega na tym, że sprawdzane wyjątki są sprawdzane podczas kompilacji, podczas gdy wyjątki odznaczone są sprawdzane w czasie wykonywania.

Przeczytaj ten article, aby uzyskać przejrzysty pomysł.

0

More Details

Korzystanie sprawdzone wyjątki, gdy kod klienta może zająć trochę przydatnych akcję odzyskiwania na podstawie informacji zawartych w wyjątku. Użyj niezaznaczonego wyjątku, gdy kod klienta nie może nic zrobić. Na przykład przekonwertuj swój wyjątek SQLException do innego zaznaczonego wyjątku, jeśli kod klienta może go odzyskać i przekonwertować wyjątek SQLException do wyjątku niezaznaczonego (tj. Wyjątku RuntimeException), jeśli kod klienta nie może nic z tym zrobić.

1

Pięć przykładów sprawdzonego wyjątku i niezaznaczonego wyjątku.

Unchecked Exception 
    -- NullPointerException 
    -- ArrayIndexOutofBound 
    -- IllegalArgument Exception 
    -- ClassCastException 
    -- IllegalStateException 
    -- ConcurrentModificationException 

Checked Exception Five Example 
    -- FileNotFoundException 
    -- ParseException 
    -- ClassNotFoundException 
    -- CloneNotSupportException 
    -- SQLException 
Powiązane problemy