1. Typer af undtagelser

Alle undtagelser er opdelt i 4 typer, som faktisk er klasser, der arver hinanden.

Throwableklasse

Basisklassen for alle undtagelser er Throwableklassen. Klassen Throwableindeholder koden, der skriver den aktuelle opkaldsstak (staksporing af den aktuelle metode) til et array. Vi lærer, hvad et stakspor er lidt senere.

Kasteoperatøren kan kun acceptere et objekt, der stammer fra klassenThrowable . Og selvom du teoretisk kan skrive kode som throw new Throwable();, er der normalt ingen, der gør dette. Klassens hovedformål Throwableer at have en enkeltforælderklasse for alle undtagelser.

Errorklasse

Den næste undtagelsesklasse er Errorklassen, som direkte arver Throwableklassen. Java-maskinen opretter objekter af Errorklassen (og dens efterkommere), når der er opstået alvorlige problemer . For eksempel en hardwarefejl, utilstrækkelig hukommelse osv.

Normalt, som programmør, er der ikke noget, du kan gøre i en situation, hvor en sådan fejl (den slags, som en Errorskal kastes for) er opstået i programmet: disse fejl er for alvorlige. Det eneste du kan gøre er at give brugeren besked om, at programmet går ned og/eller skrive alle kendte oplysninger om fejlen til programloggen.

Exceptionklasse

Klasserne Exceptionog RuntimeExceptioner til almindelige fejl, der opstår i driften af ​​mange metoder. Målet med hver kastet undtagelse er at blive fanget af en catchblok, der ved, hvordan man håndterer den korrekt.

Når en metode af en eller anden grund ikke kan fuldføre sit arbejde, skal den straks underrette den kaldende metode ved at kaste en undtagelse af den passende type.

Med andre ord, hvis en variabel er lig med null, vil metoden kaste en NullPointerException. Hvis de forkerte argumenter blev sendt til metoden, vil den kaste en InvalidArgumentException. Hvis metoden ved et uheld deler sig med nul, vil den kaste en ArithmeticException.

RuntimeExceptionklasse

RuntimeExceptionser en delmængde af Exceptions. Vi kunne endda sige, at RuntimeExceptiondet er en letvægtsversion af almindelige undtagelser ( Exception) — færre krav og begrænsninger er pålagt sådanne undtagelser

Du vil lære forskellen mellem Exceptionog RuntimeExceptionsenere.


2. Throws: kontrollerede undtagelser

Alle Java-undtagelser falder i 2 kategorier: markeret og umarkeret .

Alle undtagelser, der arver RuntimeExceptioneller Errorbetragtes som ukontrollerede undtagelser . Alle andre er kontrollerede undtagelser .

Vigtig!

Tyve år efter at kontrollerede undtagelser blev introduceret, opfatter næsten enhver Java-programmør dette som en fejl. I populære moderne rammer er 95% af alle undtagelser ikke markeret. C#-sproget, som næsten kopierede Java nøjagtigt, tilføjede ikke kontrollerede undtagelser .

Hvad er hovedforskellen mellem kontrollerede og ukontrollerede undtagelser?

Der stilles yderligere krav til kontrollerede undtagelser. Groft sagt er de disse:

Krav 1

Hvis en metode kaster en markeret undtagelse , skal den angive typen af ​​undtagelse i sin signatur . På den måde er enhver metode, der kalder den, klar over, at denne "meningsfulde undtagelse" kan forekomme i den.

Angiv markerede undtagelser efter metodeparametrene efter throwsnøgleordet (brug ikke thrownøgleordet ved en fejl). Det ser sådan ud:

type method (parameters) throws exception

Eksempel:

kontrolleret undtagelse umarkeret undtagelse
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øjre giver vores kode en umarkeret undtagelse - ingen yderligere handling er påkrævet. I eksemplet til venstre kaster metoden en markeret undtagelse, så throwsnøgleordet tilføjes til metodesignaturen sammen med typen af ​​undtagelsen.

Hvis en metode forventer at kaste flere markerede undtagelser, skal alle angives efter throwsnøgleordet, adskilt af kommaer. Rækkefølgen er ikke vigtig. 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 kalder en metode, der har kontrolleret undtagelser i sin signatur, kan du ikke ignorere, at den kaster dem.

Du skal enten fange alle sådanne undtagelser ved at tilføje catchblokke for hver enkelt, eller ved at tilføje dem til en throwsklausul for din metode.

Det er, som om vi siger: " Disse undtagelser er så vigtige, at vi må fange dem. Og hvis vi ikke ved, hvordan vi skal håndtere dem, så skal enhver, der måtte kalde vores metode, have besked om, at sådanne undtagelser kan forekomme i den.

Eksempel:

Forestil dig, at vi skriver en metode til at skabe en verden befolket af mennesker. Det oprindelige antal personer sendes som et argument. Så vi skal tilføje undtagelser, hvis der er for få mennesker.

At skabe Jorden Bemærk
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 potentielt to kontrollerede undtagelser:

  • EmptyWorldException
  • LonelyWorldException

Dette metodekald kan håndteres på 3 måder:

1. Fang ikke nogen undtagelser

Dette gøres oftest, når metoden ikke ved, hvordan man korrekt håndterer situationen.

Kode Bemærk
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
Kaldmetoden fanger ikke undtagelserne og skal informere andre om dem: den føjer dem til sin egen throwsklausul

2. Fang nogle af undtagelserne

Vi håndterer de fejl, vi kan håndtere. Men dem, vi ikke forstår, kaster vi dem op til kaldemetoden. For at gøre dette skal vi tilføje deres navn til throws-klausulen:

Kode Bemærk
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
Den, der ringer, fanger kun én markeret undtagelse — LonelyWorldException. Den anden undtagelse skal føjes til sin signatur, hvilket angiver den efter throwsnøgleordet

3. Fang alle undtagelser

Hvis metoden ikke kaster undtagelser fra den kaldende metode, så er den kaldende metode altid sikker på, at alt fungerede godt. Og det vil ikke være i stand til at foretage sig noget for at rette op på en usædvanlig situation.

Kode Bemærk
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
Alle undtagelser er fanget i denne metode. Den, der ringer, vil være sikker på, at alt gik godt.


3. Fange flere undtagelser

Programmører hader virkelig at duplikere kode. De kom endda med et tilsvarende udviklingsprincip — DRY : Don't Repeat Yourself. Men når du håndterer undtagelser, er der hyppige lejligheder, hvor en tryblok efterfølges af flere catchblokke med samme kode.

Eller der kunne være 3 catchblokke med samme kode og yderligere 2 catchblokke med anden identisk kode. Dette er en standardsituation, når dit projekt håndterer undtagelser ansvarligt.

Startende med version 7 tilføjede Java-sproget muligheden for at specificere flere typer undtagelser i en enkelt catchblok. Det ser nogenlunde sådan ud:

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

Du kan have så mange catchblokke, som du vil. En enkelt blok kan dog catchikke specificere undtagelser, der arver hinanden. Du kan med andre ord ikke skrive catch ( Exception| RuntimeExceptione), fordi RuntimeExceptionklassen arver Exception.