Dlaczego podczas wywoływania funkcji konieczne jest „zgłoszenie wyjątku”?

98
class throwseg1
{
    void show() throws Exception
    {
        throw new Exception("my.own.Exception");
    }

    void show2() throws Exception  // Why throws is necessary here ?
    {
        show();
    }

    void show3() throws Exception  // Why throws is necessary here ?
    {
        show2();
    }

    public static void main(String s[]) throws Exception  // Why throws is necessary here ?
    {
        throwseg1 o1 = new throwseg1();
        o1.show3();
    }
}

Dlaczego kompilator doniesienia, że metody show2(), show3()i main()mieć

niezgłoszony wyjątek Wyjątek, który należy przechwycić lub zadeklarować jako zgłoszony

kiedy usuwam throws Exceptionz tych metod?

nr5
źródło
2
@PaulTomblin main z pewnością można zadeklarować, aby zgłosić wyjątek. Jeśli tak się stanie, maszyna JVM zostanie zamknięta. Jest to tak bliskie zignorowaniu, jak pozwoli na to kompilator.
Taymon,
Kiedy wywołana metoda ( Methdod1 ) rzuca się Exception, musimy zdefiniować metodę wywołującą ( Method2 ) z throws Exception; jeśli nie przekazujemy tego wyjątku w metodzie wywołującej. Celem jest to, aby dać głowice do metody wywołującej ( Method3 ) od Method2 że wyjątek może być rzucony przez Method2 i należy go obsługiwać tu jeszcze może przerwać program.
Rito,
Podobnie, jeśli Method3 nie obsługuje wyjątku w swojej treści, musiała zdefiniować throws Exceptionw swojej definicji metody, aby przekazać informacje o swojej metodzie wywołującej. rozszerzenie poprzedniego komentarza
Rito

Odpowiedzi:

144

W Javie, jak być może wiesz, wyjątki można podzielić na dwie kategorie: jeden, który wymaga throwsklauzuli lub musi być obsługiwany, jeśli nie określisz jednego, i drugi, który tego nie robi. Teraz spójrz na poniższy rysunek:

wprowadź opis obrazu tutaj

W Javie możesz wrzucić wszystko, co rozszerza Throwableklasę. Nie musisz jednak określać throwsklauzuli dla wszystkich klas. Konkretnie, klas, które są albo Errorlub RuntimeExceptionczy którykolwiek z tych dwóch podklas. W twoim przypadku Exceptionnie jest podklasą klasy Errorlub RuntimeException. Jest to więc sprawdzony wyjątek i musi być określony w throwsklauzuli, jeśli nie obsługujesz tego konkretnego wyjątku. Dlatego potrzebowałeś throwsklauzuli.


Z samouczka Java :

Wyjątkiem jest zdarzenie, które występuje podczas wykonywania programu i zakłóca normalny przepływ instrukcji programu.

Teraz, jak wiesz, wyjątki są podzielone na dwie: zaznaczone i niezaznaczone. Dlaczego ta klasyfikacja?

Zaznaczony wyjątek: służą do reprezentowania problemów, które można naprawić podczas wykonywania programu. Zwykle nie są one winą programisty. Na przykład plik określony przez użytkownika nie jest czytelny lub nie ma połączenia sieciowego itp. We wszystkich tych przypadkach nasz program nie musi się kończyć, zamiast tego może wykonać działania, takie jak zaalarmowanie użytkownika lub przejście do trybu awaryjnego mechanizm (jak praca w trybie offline, gdy sieć jest niedostępna) itp.

Niezaznaczone wyjątki: Ponownie można je podzielić na dwa: błędy i wyjątki czasu wykonywania. Jednym z powodów, dla których nie można ich zaznaczyć, jest to, że są liczne i wymagane do obsługi ich wszystkich zaśmiecą nasz program i zmniejszy jego przejrzystość. Innym powodem jest:

  • Wyjątki w czasie wykonywania: Zwykle zdarzają się z powodu błędu programisty. Na przykład, jeśli występuje ArithmeticExceptiondzielenie przez zero lub ArrayIndexOutOfBoundsExceptionwystępuje, dzieje się tak, ponieważ nie jesteśmy wystarczająco ostrożni w naszym kodowaniu. Zdarzają się zwykle z powodu błędów w logice naszego programu. Dlatego muszą zostać wyczyszczone, zanim nasz program wejdzie w tryb produkcyjny. Są odznaczone w tym sensie, że nasz program musi zawieść, gdy się pojawi, abyśmy programiści mogli go rozwiązać w czasie tworzenia i testowania.

  • Błędy: Błędy to sytuacje, których zwykle program nie może naprawić. Na przykład, jeśli StackOverflowErrorwystąpi a , nasz program nie może wiele zrobić, na przykład zwiększyć rozmiar stosu wywołań funkcji programu. Lub jeśli OutOfMemoryErrorwystąpi, nie możemy zrobić wiele, aby zwiększyć ilość pamięci RAM dostępnej dla naszego programu. W takich przypadkach lepiej wyjść z programu. Dlatego nie są zaznaczone.

Aby uzyskać szczegółowe informacje, patrz:

Jomoos
źródło
z Twojej odpowiedzi wynika, że ​​klasa Error i jej podklasy oraz klasa RuntimeException i jej podklasy podlegają niezaznaczonym wyjątkom (jak System.out.println (5/0); nie ma potrzeby rzucania, ponieważ jest to runtime wyjątek, ale nadal możemy zastosować try catch) i klasa Exception jest sprawdzana, więc musimy zadeklarować klauzulę throws w tej metodzie i każdej metodzie, która ją wywołuje
nr5
Jeszcze jedno pytanie: jeśli wyjątki są podzielone na niezaznaczone i zaznaczone, szczególnie te niezaznaczone (błędy uruchomieniowe), aby uniknąć większej liczby błędów w czasie kompilacji?
nr5
@Jomoos - powiedz, że kod wewnątrz metody zgłasza wyjątek IOException. Czy w takim razie w deklaracji metody można umieścić „rzuca wyjątek”?
MasterJoe
O. Teraz rozumiem. istnieje wyjątek od reguł hierarchii wyjątków. Sprawia. Idealny. Sens. Dzięki Java.
JJS
25

Java wymaga obsługi lub deklarowania wszystkich wyjątków. Jeśli nie obsługujesz wyjątku przy użyciu bloku try / catch, należy go zadeklarować w podpisie metody.

Na przykład:

class throwseg1 {
    void show() throws Exception {
        throw new Exception();
    }
}

Powinien być zapisany jako:

class throwseg1 {
    void show() {
        try {
            throw new Exception();
        } catch(Exception e) {
            // code to handle the exception
        }
    }
}

W ten sposób możesz pozbyć się deklaracji „rzuca wyjątek” w deklaracji metody.

jebar8
źródło
7
To RuntimeExceptionznaczy wszystkie wyjątki, które nie są podklasami programu .
yshavit,
czy jest jakaś inna klasa, taka jak Exception, która jest zaznaczona?
nr5
1
Co masz na myśli? Ponieważ wszystkie obiekty wyjątków mają klasę bazową „Exception”, jeśli złapiesz obiekt „Exception” (jak w moim przykładzie), przechwyci on każdy zgłoszony wyjątek. Aby być bardziej szczegółowym (ponieważ różne wyjątki prawdopodobnie będą wymagać różnych sposobów obsługi rzeczy), powinieneś mieć wiele bloków catch.
jebar8
gdybym powiedział, że sprawdzane wyjątki muszą być obsługiwane w czasie kompilacji i przechwytywane w czasie wykonywania. Czy mam rację ? jeśli tak, to sformułowanie tego samego zdania dla Niezaznaczonego wyjątku byłoby?
nr5
@ jebar8 - mylisz Javę z .NET - w Javie przedmioty do rzucania muszą dziedziczyć Throwable(dziedziczenie Exceptionteż działa, ponieważ rozszerza Throwable, ale nie jest wymagane).
BrainSlugs83
5

throws ExceptionDeklaracja jest zautomatyzowany sposób śledzenie metod, które mogłyby rzucić wyjątek dla przewidywanych ale nieuniknionych powodów. Deklaracja jest zwykle specyficzna dla typu lub typów wyjątków, które mogą być generowane, takich jak throws IOExceptionlub throws IOException, MyException.

Wszyscy mamy lub w końcu napiszemy kod, który nieoczekiwanie zatrzymuje się i zgłasza wyjątek z powodu czegoś, czego nie przewidzieliśmy przed uruchomieniem programu, na przykład dzielenie przez zero lub indeksowanie poza zakresem. Ponieważ metoda nie spodziewała się błędów, nie można ich było „wychwycić” i obsłużyć za pomocą klauzuli try catch. Niczego nie podejrzewający użytkownicy metody również nie wiedzieliby o takiej możliwości, a ich programy również by się zatrzymały.

Gdy programista wie, że mogą wystąpić pewne typy błędów, ale chciałby obsłużyć te wyjątki poza metodą, metoda może „zgłosić” jeden lub więcej typów wyjątków do metody wywołującej zamiast ich obsługi. Gdyby programista nie zadeklarował, że metoda (mogłaby) rzucić wyjątek (lub gdyby Java nie miała możliwości zadeklarowania go), kompilator nie mógł tego wiedzieć i przyszły użytkownik metody miałby wiedzieć o tym, złapać i obsłużyć wszelkie wyjątki, które metoda może zgłosić. Ponieważ programy mogą mieć wiele warstw metod napisanych przez wiele różnych programów, śledzenie, które metody mogą generować wyjątki, staje się trudne (niemożliwe).

Mimo że Java ma możliwość deklarowania wyjątków, nadal możesz napisać nową metodę z nieobsługiwanymi i niezadeklarowanymi wyjątkami, a Java ją skompiluje i możesz ją uruchomić i mieć nadzieję na najlepsze. To, czego Java nie pozwoli ci zrobić, to skompilowanie nowej metody, jeśli używa metody, która została zadeklarowana jako wyjątek (y) wyrzucania, chyba że obsłużysz zadeklarowane wyjątki w swojej metodzie lub zadeklarujesz swoją metodę jako rzucającą to samo wyjątek (y) lub jeśli istnieje wiele wyjątków, możesz obsłużyć niektóre i wyrzucić resztę.

Gdy programista deklaruje, że metoda rzuca określony typ wyjątku, jest to po prostu zautomatyzowany sposób ostrzeżenia innych programistów za pomocą metody, że wyjątek jest możliwy. Programista może następnie zdecydować o obsłużeniu wyjątku lub przekazaniu ostrzeżenia, deklarując metodę wywołującą, która również zgłasza ten sam wyjątek. Ponieważ kompilator został ostrzeżony, że wyjątek jest możliwy w tej nowej metodzie, może automatycznie sprawdzić, czy przyszłe obiekty wywołujące nową metodę obsługują wyjątek lub deklarują go i wymuszają wystąpienie jednego lub drugiego.

Zaletą tego typu rozwiązania jest to, że gdy kompilator zgłasza Error: Unhandled exception type java.io.IOException, podaje plik i numer wiersza metody, która została zadeklarowana do zgłaszania wyjątku. Następnie możesz zdecydować się po prostu przekroczyć cenę i zadeklarować, że twoja metoda również „rzuca IOException”. Można to zrobić aż do metody głównej, w której spowodowałoby to zatrzymanie programu i zgłoszenie wyjątku użytkownikowi. Jednak lepiej jest wyłapać wyjątek i poradzić sobie z nim w przyjemny sposób, na przykład wyjaśnić użytkownikowi, co się stało i jak to naprawić. Gdy metoda przechwytuje i obsługuje wyjątek, nie musi już deklarować wyjątku. Na tym kończą się, że tak powiem.

dansalmo
źródło
4

Exceptionjest sprawdzoną klasą wyjątków. Dlatego każdy kod, który wywołuje metodę, która deklaruje, że throws Exceptionmusi ją obsłużyć lub zadeklarować.

Taymon
źródło
Każda metoda w łańcuchu jest zadeklarowana do zgłaszania wyjątku, w tym main. Więc gdzie jest problem?
Paul Tomblin,
@PaulTomblin pytam, dlaczego konieczne jest pisanie, zgłasza wyjątek w funkcjach wywołujących, wywołując funkcję, która zgłasza wyjątek
nr5
Ok, nie rozumiem, dlaczego pytasz o błąd kompilatora, którego tak naprawdę nie otrzymałeś z opublikowanego kodu. To dziwny sposób zadawania pytań.
Paul Tomblin,
0
package javaexception;


public class JavaException {
   void show() throws Exception
    {
        throw new Exception("my.own.Exception");
    }

void show2() throws Exception  // Why throws is necessary here ?
{
    show();
}

void show3() throws Exception  // Why throws is necessary here ?
{
    show2();
}
public static void main(String[] args) {

   JavaException a = new JavaException();

   try{
   a.show3();
   }catch(Exception e){
       System.out.println(e.getMessage());
   }
}

Tylko małe zmiany w twoim programie. To, co wydaje się być niezrozumiałe przez wielu w odniesieniu do głównego problemu, to to, że za każdym razem, gdy rzucasz wyjątek, musisz go obsłużyć, nie jest to konieczne w tym samym miejscu (np. Metoda show1,2,3 w twoim programie), ale najpierw musisz wywołać metodę wewnątrz „głównego”. jednym słowem jest „rzut”, musi być „złap / spróbuj”, nawet jeśli nie jest to ta sama metoda, w której występuje wyjątek.

tawess
źródło
0
void show() throws Exception
{
    throw new Exception("my.own.Exception");
}

Ponieważ w metodzie show () jest zaznaczony wyjątek, który nie jest obsługiwany w tej metodzie, do propagowania wyjątku używamy słowa kluczowego throws.

void show2() throws Exception //Why throws is necessary here ?
{
show();
}

Ponieważ używasz metody show () w metodzie show2 () i propagujesz przynajmniej wyjątek, który powinieneś tutaj obsługiwać. Jeśli nie obsługujesz tutaj wyjątku, używasz słowa kluczowego throws. To jest powód użycia słowa kluczowego throws w sygnaturze metody.

Aditya
źródło
0

Jeśli propagujesz wyjątek przez zadeklarowanie dyrektywy throws w sygnaturze bieżącej metody, to gdzieś w górę wiersza lub stosu wywołań musi zostać użyta konstrukcja try / catch do obsługi wyjątku.

Beaumont Muni
źródło
Ten komentarz należy dodać do sekcji komentarzy, ponieważ nie zawiera on sprawdzalnej odpowiedzi ani jej przykładu. - stackoverflow.com/help/how-to-answer
Paul Dawson
-1

Zasadniczo, jeśli nie obsługujesz wyjątku w tym samym miejscu, w którym go wyrzucasz, możesz użyć opcji „rzuca wyjątek” w definicji funkcji.

Shahzeb Sheikh
źródło