Szia! Utálom megemlíteni, de a programozó munkájának nagy része a hibák kezelése. Leggyakrabban a sajátját. Kiderült, hogy nincs olyan ember, aki ne hibázna. És nincsenek ilyen programok sem.
Természetesen a hiba kezelésekor a legfontosabb az okának megértése. És sok minden okozhat hibát egy programban. Valamikor a Java készítői feltették maguknak a kérdést, hogy mit kell tenni a legvalószínűbb programozási hibákkal? Ezek teljes elkerülése nem reális, a programozók képesek olyan dolgokat írni, amiket el sem tudsz képzelni. :) Tehát egy mechanizmust kell adnunk a nyelvnek a hibákkal való munkavégzéshez. Más szóval, ha hiba van a programban, szükség van valamilyen szkriptre a következő lépésekhez. Pontosan mit kell tennie egy programnak hiba esetén? Ma ezzel a mechanizmussal fogunk megismerkedni. Ezt úgy hívják, hogy " kivételek a Java-ban ".
A kód, ahol a programozó úgy véli, hogy kivétel előfordulhat, a blokkba kerül

Mi a kivétel?
Kivételt képez a program futása közben fellépő rendkívüli, nem tervezett helyzet. Sok kivétel van. Például olyan kódot írt, amely szöveget olvas ki egy fájlból, és megjeleníti az első sort.
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
}
}
De mi van, ha nincs ilyen fájl! A program kivételt generál: FileNotFoundException
. Kimenet: Kivétel a "fő" szálban java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (A rendszer nem találja a megadott elérési utat) A Java nyelvben minden kivételt külön osztály képvisel. Mindezek a kivételosztályok egy közös „ősből” – a Throwable
szülőosztályból – származnak. A kivételosztály neve általában tömören tükrözi, hogy miért történt a kivétel:
FileNotFoundException
(a fájl nem található)ArithmeticException
(egy matematikai művelet végrehajtása során kivétel történt)ArrayIndexOutOfBoundsException
(az index túl van a tömb határain). Ez a kivétel például akkor fordul elő, ha egy olyan tömb 23. pozícióját próbálja megjeleníteni, amely csak 10 elemből áll.
Exception in thread "main"
Uhhhh. :/ Ez nem sokat segít. Nem világos, hogy mit jelent a hiba, és honnan ered. Itt nincs hasznos információ. De a Java kivételosztályainak sokfélesége megadja a programozónak azt, ami a legfontosabb: a hiba típusát és valószínű okát (az osztály nevébe ágyazva). Egészen más dolog látni
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (The system cannot find the specified path)
Azonnal világos, hogy mi lehet a probléma, és hol kell kezdeni az ásást a probléma megoldása érdekében! A kivételek, mint bármely osztály példányai, objektumok.
A kivételek elfogása és kezelése
A Java speciális kódblokkokat tartalmaz a kivételekkel:try
, catch
és finally
. 
try
. Ez nem jelenti azt, hogy itt kivétel lesz. Ez azt jelenti, hogy itt előfordulhat, és a programozó tisztában van ezzel a lehetőséggel. A várt hibatípus a blokkba kerül catch
. Ez tartalmazza az összes kódot is, amelyet kivétel esetén végre kell hajtani. Íme egy példa:
public static void main(String[] args) throws IOException {
try {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
System.out.println("Error! File not found!");
}
}
Kimenet: Hiba! Fájl nem található! A kódunkat két blokkba helyezzük. Az első blokkban arra számítunk, hogy "A fájl nem található" hiba léphet fel. Ez a try
blokk. A másodikban elmondjuk a programnak, hogy mit tegyen, ha hiba történik. És a konkrét hibatípus: FileNotFoundException
. Ha egy másik kivételosztályt teszünk a blokk zárójelébe catch
, akkor FileNotFoundException
nem lesz elkapva.
public static void main(String[] args) throws IOException {
try {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (ArithmeticException e) {
System.out.println("Error! File not found!");
}
}
Kimenet: Kivétel a "main" szálban java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (A rendszer nem találja a megadott elérési utat) A catch
blokkban lévő kód nem futott, mert "konfiguráltuk" ezt a blokkot elkapni ArithmeticException
, és a try
blokkban lévő kód más típusút dobott: FileNotFoundException
. Nem írtunk kódot a kezeléshez FileNotFoundException
, így a program megjeleníti az alapértelmezett információkat FileNotFoundException
. Itt három dologra kell figyelni. Első számú. Ha a blokk valamelyik sorában kivétel történik try
, a következő kód nem kerül végrehajtásra. A program végrehajtása azonnal "ugrik" a catch
mondatra. Például:
public static void main(String[] args) {
try {
System.out.println("Divide by zero");
System.out.println(366/0);// This line of code will throw an exception
System.out.println("This");
System.out.println("code");
System.out.println("will not");
System.out.println("be");
System.out.println("executed!");
} catch (ArithmeticException e) {
System.out.println("The program jumped to the catch block!");
System.out.println("Error! You can't divide by zero!");
}
}
Kimenet: osztás nullával A program a fogóblokkra ugrott! Hiba! Nem lehet nullával osztani! A blokk második sorában try
megpróbálunk 0-val osztani, ami egy ArithmeticException
. Következésképpen a try
blokk 3-9. sorai nem kerülnek végrehajtásra. Mint mondtuk, a program azonnal megkezdi a catch
blokk végrehajtását. Második. Több blokk is lehet catch
. Ha a blokkban lévő kód nem egy, hanem több különböző típusú kivételt dobhat, mindegyikhez try
írhat egy blokkot.catch
public static void main(String[] args) throws IOException {
try {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
System.out.println(366/0);
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
System.out.println("Error! File not found!");
} catch (ArithmeticException e) {
System.out.println("Error! Division by 0!");
}
}
Ebben a példában két blokkot írtunk catch
. Ha FileNotFoundException
a blokkban a előfordul try
, akkor az első catch
blokk kerül végrehajtásra. Ha ArithmeticException
előfordul, a második blokk végrehajtásra kerül. 50 blokkot írhat catch
, ha akar. Természetesen jobb, ha nem írunk olyan kódot, amely 50 féle kivételt adhat. :) Harmadik. Honnan tudja, hogy a kód mely kivételeket okozhat? Nos, lehet, hogy néhányat kitalálsz, de lehetetlen, hogy mindent a fejedben tarts. A Java fordító tehát ismeri a leggyakoribb kivételeket és azokat a helyzeteket, ahol ezek előfordulhatnak. Például, ha olyan kódot ír, amelyről a fordító tudja, hogy kétféle kivételt okozhat, akkor a kód addig nem fordul le, amíg nem kezeli őket. Az alábbiakban erre láthatunk példákat. Most néhány szó a kivételkezelésről. A kivételek kezelésének két módja van. Az elsővel már találkoztunk: a metódus magát a kivételt is képes kezelni egy blokkban catch()
. Van egy második lehetőség: a metódus újra feldobhatja a kivételt a hívási verembe. Az mit jelent? Például van egy osztályunk ugyanazzal a printFirstString()
metódussal, amely beolvas egy fájlt és megjeleníti annak első sorát:
public static void printFirstString(String filePath) {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String firstString = reader.readLine();
System.out.println(firstString);
}
Jelenleg a kódunk nem fordít le, mert vannak kezeletlen kivételek. Az 1. sorban adja meg a fájl elérési útját. A fordító tudja, hogy egy ilyen kód könnyen előállíthat egy FileNotFoundException
. A 3. sorban olvassa el a szöveget a fájlból. Ez a folyamat könnyen (bemeneti/kimeneti hibát) eredményezhet IOException
. Most a fordító azt mondja neked: "Haver, nem hagyom jóvá ezt a kódot, és nem fogom lefordítani addig, amíg meg nem mondod, mit tegyek, ha ezen kivételek valamelyike előfordul. És minden bizonnyal megtörténhet az általad írt kód alapján. !" Ezt nem lehet megkerülni: mindkettőt kezelni kell! Az első kivételkezelési módszerről már tudunk: a kódunkat egy blokkba kell helyeznünk, try
és két catch
blokkot kell hozzáadnunk:
public static void printFirstString(String filePath) {
try {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
System.out.println("Error, file not found!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("File input/output error!");
e.printStackTrace();
}
}
De nem ez az egyetlen lehetőség. Egyszerűen magasabbra dobhatjuk a kivételt ahelyett, hogy hibakezelő kódot írnánk a metódusba. throws
Ez a metódus deklarációjában található kulcsszó használatával történik :
public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String firstString = reader.readLine();
System.out.println(firstString);
}
A kulcsszó után throws
egy vesszővel elválasztott listát jelezünk az összes kivételtípusról, amelyet a metódus dobhat. Miért? Ha valaki meg akarja hívni a printFirstString()
metódust a programban, akkor neki (nem neked) kell végrehajtania a kivételkezelést. Tegyük fel például, hogy a program más részében az egyik kollégája írt egy metódust, amely meghívja az Ön printFirstString()
metódusát:
public static void yourColleagueMethod() {
// Your colleague's method does something
//...and then calls your printFirstString() method with the file it needs
printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
Hibát kapunk! Ez a kód nem fordítható le! Nem írtunk kivételkezelő kódot a metódusban printFirstString()
. Ennek eredményeként ez a feladat most a módszert alkalmazók vállára hárul. Más szavakkal, a methodWrittenByYourColleague()
metódusnak most ugyanaz a 2 lehetősége van: vagy blokkot kell használnia try-catch
mindkét kivétel kezelésére, vagy újra kell dobnia őket.
public static void yourColleagueMethod() throws FileNotFoundException, IOException {
// The method does something
//...and then calls your printFirstString() method with the file it needs
printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
A második esetben a hívásverem következő metódusának – a hívónak methodWrittenByYourColleague()
– kell kezelnie a kivételeket. Ezért hívjuk ezt "a kivétel feldobásának vagy átengedésének". Ha a kivételeket felfelé dobja a kulcsszó használatával throws
, a kód lefordításra kerül. Ezen a ponton úgy tűnik, hogy a fordító azt mondja: "Rendben, oké. A kódod egy csomó lehetséges kivételt tartalmaz, de lefordítom. De visszatérünk ehhez a beszélgetéshez!" És ha olyan metódust hívunk meg, amelyben vannak kezeletlen kivételek, a fordító beváltja ígéretét, és újra emlékeztet rájuk. Végül a blokkról beszélünk finally
(elnézést a szójátékért). Ez a try-catch-finally
kivételkezelési triumvirátus utolsó része..
public static void main(String[] args) throws IOException {
try {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
System.out.println("Error! File not found!");
e.printStackTrace();
} finally {
System.out.println ("And here's the finally block!");
}
}
Ebben a példában a finally
blokkon belüli kód mindkét esetben végrehajtásra kerül. Ha a blokkban lévő kód try
teljes egészében lefut, kivételek nélkül, akkor a finally
blokk a végén lefut. Ha a try
blokkon belüli kódot egy kivétel megszakítja és a program a blokkra ugrik catch
, a finally
blokk továbbra is a catch
blokkon belüli kód után fut. Miért van erre szükség? Fő célja a kötelező kód végrehajtása: olyan kód, amelyet a körülményektől függetlenül végre kell hajtani. Például gyakran felszabadít néhány, a program által használt erőforrást. A kódunkban megnyitunk egy adatfolyamot, hogy információt olvassunk a fájlból és továbbítsuk az objektumnak BufferedReader
. Le kell zárnunk olvasónkat, és fel kell szabadítani a forrásokat. Ezt mindentől függetlenül meg kell tenni – amikor a program megfelelően működik, és amikor kivételt dob. A finally
blokk nagyon kényelmes hely erre:
public static void main(String[] args) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
System.out.println ("And here's the finally block!");
if (reader != null) {
reader.close();
}
}
}
Most már biztosak vagyunk abban, hogy gondoskodni fogunk az erőforrásokról, függetlenül attól, hogy mi történik a program futása közben. :) Nem csak ennyit kell tudni a kivételekről. A hibakezelés rendkívül fontos téma a programozásban. Nagyon sok cikket szentelnek neki. A következő leckében megtudjuk, milyen típusú kivételek léteznek, és hogyan hozhat létre saját kivételeket. :) Majd találkozunk!
További olvasnivalók: |
---|
GO TO FULL VERSION