1. Typer unntak

Alle unntak er delt inn i 4 typer, som faktisk er klasser som arver hverandre.

Throwableklasse

Basisklassen for alle unntak er Throwableklassen. Klassen Throwableinneholder koden som skriver gjeldende anropsstabel (stabelsporing av gjeldende metode) til en matrise. Vi får vite hva en stabelsporing er litt senere.

Kast - operatøren kan bare godta et objekt som stammer fra Throwableklassen. Og selv om du teoretisk kan skrive kode som throw new Throwable();, er det vanligvis ingen som gjør dette. Hovedformålet med Throwableklassen er å ha en enkeltforelderklasse for alle unntak.

Errorklasse

Den neste unntaksklassen er Errorklassen, som direkte arver Throwableklassen. Java-maskinen lager objekter av Errorklassen (og dens etterkommere) når det har oppstått alvorlige problemer . For eksempel en maskinvarefeil, utilstrekkelig minne, etc.

Vanligvis, som programmerer, er det ingenting du kan gjøre i en situasjon der en slik feil (den typen en Errorbør kastes for) har oppstått i programmet: disse feilene er for alvorlige. Alt du kan gjøre er å varsle brukeren om at programmet krasjer og/eller skrive all kjent informasjon om feilen til programloggen.

Exceptionklasse

Klassene Exceptionog RuntimeExceptioner for vanlige feil som skjer i driften av mange metoder. Målet med hvert kastet unntak er å bli fanget av en catchblokk som vet hvordan den skal håndteres på riktig måte.

Når en metode av en eller annen grunn ikke kan fullføre arbeidet, bør den umiddelbart varsle kallemetoden ved å kaste et unntak av den aktuelle typen.

Med andre ord, hvis en variabel er lik null, vil metoden kaste en NullPointerException. Hvis de uriktige argumentene ble sendt til metoden, vil den kaste en InvalidArgumentException. Hvis metoden ved et uhell deler på null, vil den kaste en ArithmeticException.

RuntimeExceptionklasse

RuntimeExceptionser en undergruppe av Exceptions. Vi kan til og med si at RuntimeExceptiondet er en lett versjon av vanlige unntak ( Exception) — færre krav og begrensninger er pålagt slike unntak

Du vil lære forskjellen mellom Exceptionog RuntimeExceptionsenere.


2. Throws: sjekket unntak

Alle Java-unntak faller inn i 2 kategorier: avmerket og uavmerket .

Alle unntak som arver RuntimeExceptioneller Errorregnes som ukontrollerte unntak . Alle andre er sjekkede unntak .

Viktig!

Tjue år etter at sjekkede unntak ble introdusert, ser nesten alle Java-programmerere på dette som en feil. I populære moderne rammeverk er 95 % av alle unntak umerket. C#-språket, som nesten kopierte Java nøyaktig, la ikke til sjekkede unntak .

Hva er hovedforskjellen mellom sjekkede og ukontrollerte unntak?

Det stilles tilleggskrav til sjekkede unntak. Grovt sett er de disse:

Krav 1

Hvis en metode kaster et sjekket unntak , må den angi typen unntak i signaturen . På den måten er hver metode som kaller den klar over at dette "meningsfulle unntaket" kan forekomme i den.

Angi avmerkede unntak etter metodeparameterne etter throwsnøkkelordet (ikke bruk thrownøkkelordet ved en feiltakelse). Det ser omtrent slik ut:

type method (parameters) throws exception

Eksempel:

sjekket unntak uavmerket unntak
public void calculate(int n) throws Exception
{
   if (n == 0)
      throw new Exception("n is null!");
}
public void calculate(n)
{
   if (n == 0)
      throw new RuntimeException("n is null!");
}

I eksemplet til høyre gir koden vår et ukontrollert unntak - ingen ekstra handling er nødvendig. I eksempelet til venstre kaster metoden et avmerket unntak, så throwsnøkkelordet legges til metodesignaturen sammen med typen unntak.

Hvis en metode forventer å gi flere avmerkede unntak, må alle spesifiseres etter throwsnøkkelordet, atskilt med komma. Rekkefølgen er ikke viktig. Eksempel:

public void calculate(int n) throws Exception, IOException
{
   if (n == 0)
      throw new Exception("n is null!");
   if (n == 1)
      throw new IOException("n is 1");
}

Krav 2

Hvis du kaller en metode som har sjekket unntak i signaturen, kan du ikke se bort fra det faktum at den kaster dem.

Du må enten fange opp alle slike unntak ved å legge til catchblokker for hver enkelt, eller ved å legge dem til en throwsklausul for metoden din.

Det er som om vi sier: " Disse unntakene er så viktige at vi må fange dem. Og hvis vi ikke vet hvordan vi skal håndtere dem, må alle som kan ringe metoden vår få beskjed om at slike unntak kan forekomme i den.

Eksempel:

Tenk deg at vi skriver en metode for å skape en verden befolket av mennesker. Det opprinnelige antallet personer sendes som et argument. Så vi må legge til unntak hvis det er for få personer.

Skaper jorden Merk
public void createWorld(int n) throws EmptyWorldException, LonelyWorldException
{
   if (n == 0)
      throw new EmptyWorldException("There are no people!");
   if (n == 1)
      throw new LonelyWorldException ("There aren't enough people!");
   System.out.println("A wonderful world was created. Population: " + n);
}
Metoden kaster potensielt to sjekkede unntak:

  • EmptyWorldException
  • LonelyWorldException

Dette metodekallet kan håndteres på 3 måter:

1. Ikke ta noen unntak

Dette gjøres oftest når metoden ikke vet hvordan den skal håndtere situasjonen på riktig måte.

Kode Merk
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
Anropsmetoden fanger ikke opp unntakene og må informere andre om dem: den legger dem til sin egen throwsklausul

2. Fang noen av unntakene

Vi håndterer feilene vi kan håndtere. Men de vi ikke forstår, kaster vi dem opp til kallemetoden. For å gjøre dette, må vi legge til navnet deres i throws-klausulen:

Kode Merk
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
Den som ringer fanger bare ett avkrysset unntak — LonelyWorldException. Det andre unntaket må legges til signaturen, og angi det etter throwsnøkkelordet

3. Fang alle unntak

Hvis metoden ikke gir unntak fra anropsmetoden, er anropsmetoden alltid sikker på at alt fungerte bra. Og det vil ikke være i stand til å iverksette tiltak for å fikse en eksepsjonell situasjon.

Kode Merk
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
Alle unntak er fanget opp i denne metoden. Den som ringer vil være trygg på at alt gikk bra.


3. Fange flere unntak

Programmerere hater virkelig å duplisere kode. De kom til og med opp med et tilsvarende utviklingsprinsipp — DRY : Don't Repeat Yourself. Men når du håndterer unntak, er det hyppige tilfeller der en tryblokk blir fulgt av flere catchblokker med samme kode.

Eller det kan være 3 catchblokker med samme kode og ytterligere 2 catchblokker med annen identisk kode. Dette er en standardsituasjon når prosjektet ditt håndterer unntak på en ansvarlig måte.

Fra og med versjon 7, i Java-språket lagt til muligheten til å spesifisere flere typer unntak i en enkelt catchblokk. Det ser omtrent slik ut:

try
{
   // Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
   // Exception handling code
}

Du kan ha så mange catchblokker du vil. En enkelt blokk kan imidlertid catchikke spesifisere unntak som arver hverandre. Du kan med andre ord ikke skrive catch ( Exception| RuntimeExceptione), fordi RuntimeExceptionklassen arver Exception.