1. A kivételek típusai

A kivételek típusai

Minden kivétel 4 típusra oszlik, amelyek valójában egymást öröklik osztályok.

Throwableosztály

Az összes kivétel alaposztálya az Throwableosztály. Az Throwableosztály tartalmazza azt a kódot, amely az aktuális hívási veremet (az aktuális metódus veremnyomát) egy tömbbe írja. Kicsit később megtudjuk, mi az a veremnyom.

A dobás operátor csak olyan objektumot tud elfogadni, amely az osztályból származik Throwable. És bár elméletileg írhat olyan kódot, mint a throw new Throwable();, ezt általában senki sem csinálja. Az osztály fő célja, Throwablehogy minden kivételre egyszülős osztály legyen.

Errorosztály

A következő kivételosztály az Errorosztály, amely közvetlenül örökli az Throwableosztályt. A Java gép létrehozza az osztály objektumait Error(és leszármazottjait), ha komoly problémák lépnek fel . Például hardverhiba, elégtelen memória stb.

Általában programozóként nem tud mit tenni olyan helyzetben, amikor egy ilyen hiba (olyan, amiért egy-t Errorkell dobni) történt a programban: ezek a hibák túl súlyosak. Nem tehet mást, mint értesíti a felhasználót, hogy a program összeomlik, és/vagy a hibáról minden ismert információt beír a programnaplóba.

Exceptionosztály

A Exceptionés RuntimeExceptionosztályok a sok metódus működése során előforduló gyakori hibákra szolgálnak. Minden dobott kivétel célja, hogy elkapja egy catchblokk, amely tudja, hogyan kell megfelelően kezelni.

Ha egy metódus valamilyen okból nem tudja befejezni a munkáját, azonnal értesítenie kell a hívó metódust a megfelelő típusú kivétel dobásával.

Más szóval, ha egy változó egyenlő -val null, akkor a metódus egy -et dob NullPointerException. Ha helytelen argumentumokat adtunk át a metódusnak, akkor egy InvalidArgumentException. Ha a metódus véletlenül nullával oszt, akkor egy ArithmeticException.

RuntimeExceptionosztály

RuntimeExceptionsrészhalmaza a Exceptions. Akár azt is mondhatnánk, hogy RuntimeExceptiona szokásos kivételek ( ) könnyített változata Exception– kevesebb követelmény és korlátozás vonatkozik az ilyen kivételekre

ExceptionKésőbb megtanulod, mi a különbség a és a között RuntimeException.


2. Throws: ellenőrzött kivételek

Dobások: ellenőrzött kivételek

Minden Java-kivétel 2 kategóriába sorolható: bejelölt és nem bejelölt .

Minden kivétel, amely örökli a RuntimeExceptionvagy a vagy a Errorbejelöletlen kivételeket . Az összes többi ellenőrzött kivétel .

Fontos!

Húsz évvel az ellenőrzött kivételek bevezetése után szinte minden Java programozó ezt hibának tartja. A népszerű modern keretrendszerekben a kivételek 95%-a nincs bejelölve. A C# nyelv, amely majdnem pontosan másolta a Java-t, nem adott hozzá ellenőrzött kivételeket .

Mi a fő különbség a bejelölt és a nem ellenőrzött kivételek között?

Az ellenőrzött kivételekre további követelmények vonatkoznak . Nagyjából ezek a következők:

1. követelmény

Ha egy metódus ellenőrzött kivételt dob , akkor az aláírásában jeleznie kell a kivétel típusát . Így minden hívó metódus tudatában van annak, hogy ez az "értelmes kivétel" előfordulhat benne.

A bejelölt kivételeket a kulcsszó után a metódusparaméterekthrows után tüntesse fel (ne használja throwvéletlenül a kulcsszót). Valahogy így néz ki:

type method (parameters) throws exception

Példa:

ellenőrzött kivétel ellenőrizetlen kivétel
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!");
}

A jobb oldali példában a kódunk egy ellenőrizetlen kivételt dob ​​– nincs szükség további teendőkre. A bal oldali példában a metódus ellenőrzött kivételt dob, így a throwskulcsszó hozzáadódik a metódus aláírásához a kivétel típusával együtt.

Ha egy metódus több ellenőrzött kivételt vár , akkor mindegyiket meg kell adni a throwskulcsszó után, vesszővel elválasztva. A sorrend nem fontos. Példa:

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");
}

2. követelmény

Ha olyan metódust hív meg, amelynek aláírása kivételeket ellenőrzött , nem hagyhatja figyelmen kívül azt a tényt, hogy kidobja azokat.

Az összes ilyen kivételt meg kell kapnia úgy, hogy catchmindegyikhez blokkokat ad hozzá, vagy hozzá kell adnia őket athrows metódushoz tartozó záradékhoz .

Mintha azt mondanánk: " Ezek a kivételek annyira fontosak, hogy meg kell fognunk őket. És ha nem tudjuk, hogyan kezeljük őket, akkor mindenkit értesíteni kell, aki hívja a módszerünket, hogy előfordulhatnak benne ilyen kivételek.

Példa:

Képzeld el, hogy írunk egy módszert egy emberek által lakott világ létrehozására. A kezdeti létszámot adják át érvként. Tehát kivételeket kell hozzáadnunk, ha túl kevés ember van.

Föld teremtése jegyzet
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);
}
A módszer potenciálisan két ellenőrzött kivételt dob:

  • EmptyWorldException
  • LonelyWorldException

Ez a metódushívás háromféleképpen kezelhető:

1. Ne ragadj el semmilyen kivételt

Ezt leggyakrabban akkor teszik meg, ha a módszer nem tudja, hogyan kell megfelelően kezelni a helyzetet.

Kód jegyzet
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
A hívási metódus nem fogja fel a kivételeket, és tájékoztatnia kell róluk másokat: hozzáadja azokat a saját throwszáradékához

2. Fogjon meg néhány kivételt

Mi kezeljük azokat a hibákat, amelyeket kezelni tudunk. De akiket nem értünk, azokat feldobjuk a hívásmódra. Ehhez hozzá kell adnunk a nevüket a dobás záradékhoz:

Kód jegyzet
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
A hívó csak egy ellenőrzött kivételt észlel – LonelyWorldException. A másik kivételt hozzá kell adni az aláírásához, a throwskulcsszó után jelezve

3. Fogja meg az összes kivételt

Ha a metódus nem tesz kivételt a hívó metódus alól, akkor a hívó metódus mindig biztos abban, hogy minden jól működött. És nem tud semmilyen intézkedést tenni a kivételes helyzetek megoldására.

Kód jegyzet
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
Ez a módszer minden kivételt megragad. A hívó biztos abban, hogy minden rendben ment.


3. Burkolási kivételek

Az ellenőrzött kivételek elméletben menőnek tűntek, de a gyakorlatban óriási csalódásnak bizonyultak.

Tegyük fel, hogy van egy rendkívül népszerű módszer a projektjében. A programodban több száz helyről hívják. És úgy dönt, hogy hozzáad egy új ellenőrzött kivételt. És könnyen lehet, hogy ez az ellenőrzött kivétel valóban fontos és annyira különleges, hogy csak a main()metódus tudja, mit kell tenni, ha elkapják.

Ez azt jelenti, hogy hozzá kell adnia a bejelölt kivételt throwsminden olyan metódus záradékához, amely a szupernépszerű metódusát hívja meg . Valamint throwsaz összes olyan metódus záradékában, amely ezeket a metódusokat hívja. És azokról a módszerekről, amelyek ezeket a módszereket hívják.

Ennek eredményeként throwsa projektben a metódusok felének záradékai új ellenőrzött kivételt kapnak. És természetesen a projektjét tesztek fedik le, és most a tesztek nem fordítódnak le. És most szerkesztened kell a dobások záradékait is a tesztekben.

Ezután az összes kódot (a több száz fájlban lévő összes változást) más programozóknak át kell nézniük. És ezen a ponton feltesszük magunknak a kérdést, hogy miért hajtottunk végre annyi véres változtatást a projekten? Munkanap(ok) és hibás tesztek – mindez csak egy ellenőrzött kivétel hozzáadásának kedvéért ?

És természetesen továbbra is vannak problémák az örökléssel és a módszer felülbírálásával kapcsolatban. Az ellenőrzött kivételekből származó problémák sokkal nagyobbak, mint a haszon. A lényeg az, hogy ma már kevesen szeretik és kevesen használják.

Azonban még mindig sok olyan kód van (beleértve a szabványos Java könyvtári kódot is), amely ezeket az ellenőrzött kivételeket tartalmazza. Mi a teendő velük? Nem hagyhatjuk figyelmen kívül őket, és nem tudjuk, hogyan kezeljük őket.

A Java programozók azt javasolták, hogy az ellenőrzött kivételeket csomagolja be RuntimeException. Más szóval, fogja meg az összes ellenőrzött kivételt, majd hozzon létre nem ellenőrzött kivételeket (például RuntimeException), és dobja el őket. Ez valahogy így néz ki:

try
{
   // Code where a checked exception might occur
}
catch(Exception exp)
{
   throw new RuntimeException(exp);
}

Nem túl szép megoldás, de nincs itt semmi bűnöző: a kivételt egyszerűen egy RuntimeException.

Ha szükséges, onnan könnyen visszakeresheti. Példa:

Kód jegyzet
try
{
   // Code where we wrap the checked exception
   // in a RuntimeException
}
catch(RuntimeException e)
{
   Throwable cause = e.getCause();
   if (cause instanceof Exception)
   {
      Exception exp = (Exception) cause;
      // Exception handling code goes here
   }
}







A kivétel tárolása az RuntimeExceptionobjektumon belül. A causeváltozó esetleg null

Meghatározza a típusát, és konvertálja ellenőrzött kivételtípussá.


4. Több kivétel elkapása

A programozók nagyon utálják a kód megkettőzését. Még egy megfelelő fejlesztési elvet is kitaláltak: Ne ismételd magad (SZÁRAZ) . A kivételek kezelésekor azonban gyakran előfordulnak olyan esetek, amikor egy blokkot több azonos kódú blokk trykövet .catch

Vagy lehet 3 catchblokk ugyanazzal a kóddal és további 2 catchblokk más azonos kóddal. Ez egy szokásos helyzet, amikor a projekt felelősen kezeli a kivételeket.

A 7-es verziótól kezdődően a Java nyelv több típusú kivételt is megadhat egyetlen blokkban catch. Valahogy így néz ki:

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

Annyi blokkja lehet, amennyit catchcsak akar. Egyetlen catchblokk azonban nem határozhat meg olyan kivételeket, amelyek öröklik egymást. Más szóval, nem írhatod a catch ( Exception| RuntimeExceptione) kifejezést, mert az RuntimeExceptionosztály örökli a -t Exception.



5. Egyéni kivételek

Mindig létrehozhat saját kivételosztályt. Egyszerűen létrehoz egy osztályt, amely örökli az RuntimeExceptionosztályt. Valahogy így fog kinézni:

class ClassName extends RuntimeException
{
}

Megbeszéljük a részleteket, miközben megtanulja az OOP-t, az öröklődést, a konstruktorokat és a metódusok felülbírálását.

Ha azonban csak egy ilyen egyszerű osztályod van (teljesen kód nélkül), akkor is dobhatsz kivételeket az alapján:

Kód jegyzet
class Solution
{
   public static void main(String[] args)
   {
      throw new MyException();
   }
}

class MyException extends RuntimeException
{
}




Dobj egy ellenőrizetlen MyException .

A Java Multithreading küldetés során mélyen elmerülünk a saját egyéni kivételeinkkel való munka során.