Felhasználói eszközök

Eszközök a webhelyen


oktatas:programozas:java:java_kivetelek

< Java

Java kivételek

Bevezetés

Ha a program természetes végrehajtása során probléma lép fel, akkor egy kivétel keletkezik. Vannak osztályok amelyeknek használata esetén kötelező a kivételt kezelni, ezek az ellenőrzött kivételek.

A kivételekkel két dolgot tehetünk: elkapjuk, vagy eldobjuk (továbbengedjük).

Ha egy metódusban hiba keletkezik, akkor létrehoz egy objektumot, amelyet átad a futtatókörnyezetnek. Ez a kivételobjektum tartalmazza a hiba leírását, annak típusát, a program állapotát. Ennek az objektumnak a létrehozása a kivételdobás.

Kivétel Leírás
ellenőrzött Ha egy metódus kivételt dob, a fordító hibát jelez,
ha nincs try-catch kód.
futási idejű
(ellenőrizetlen)
Nem kötelező catch blokk
A java.lang.RuntimeException osztályból származik.

A kivétel elkapása

A try utasítással megpróbálunk végrehajtani egy kódot. Ha kód kivételt dob, akkor azt a catch utasítással elkapjuk. A catch utáni részben pedig kezeljük.

try {
    //kód amit megpróbálunk végrehajtani
}catch(Exception e){
    //mit teszünk, ha kivétel keletkezett
}

Az Exception osztály egy általános kivételosztály. Minden kivétel ebből származik. Az e objektum keletkezik bármilyen kivétel esetén, ami Exception típusú lesz. Ez azt is jelenti, hogy minden kivételt elkap.

Az Exception helyett megadhatunk konkrét kivételeket is. Az IOException például fájlba írás során használjuk. Ha ilyen kivételeket szeretnénk elkapni, az e objektumot tegyük IOException típusúvá:

try {
    //fájlba író kód amit megpróbálunk végrehajtani
}catch(IOException e){
    //mit teszünk, ha a fájlba írás sikertelen
}

Konkrét példa:

try {
    FileWriter fw = new FileWriter("adat.txt", true);
    fw.write("bármi\n");	
    fw.close();
}catch(IOException e){
    System.err.println("Hiba! A fájlbaírás sikertelen!");
    System.err.println(e.getMessage());
}

Néhány gyakran használt kivétel

  • IOException
  • GeneralSecurityException
  • ClassNotFoundException
  • ArithmeticException
  • ArrayIndexOutOfBoundsException
  • ArrayStoreException
  • ClassNotFoundException
  • EnumConstantNotPresentException
  • Exception
  • IllegalAccessException
  • IllegalArgumentException
  • IllegalThreadStateException
  • IndexOutOfBoundsException
  • InstantiationException
  • InterruptedException
  • NegativeArraySizeException
  • NoSuchFieldException
  • NoSuchMethodException
  • NullPointerException
  • NumberFormatException
  • RuntimeException
  • SecurityException
  • StringIndexOutOfBoundsException
  • TypeNotPresentException
  • UnsupportedOperation

Több kivétel elkapása

Egymás után több kivételt is elkaphatunk:

try {
   ... kód ...
}catch (IOException e){
    e.printStackTrace();
}catch (GeneralSecurityException e){
    e.printStackTrace();
}catch (ClassNotFoundException e){
    e.printStackTrace();
}

Kivételek üzenetei

Nézzük meg egy FileNotFoundException esetén mit kapunk ha csak simán kiíratjuk a ex tartalmát:

try {
    File file = new File("adat.txt");
    Scanner scanner = new Scanner(file);
}catch(FileNotFoundException ex) {
    System.err.println(ex);
}
java.io.FileNotFoundException: adat.txt (Nincs ilyen fájl vagy könyvtár)

Most nézzük meg, mit kapunk, ha az egész hívásverem tartalmát kiíratjuk:

try {
    File file = new File("adat.txt");
    Scanner scanner = new Scanner(file);
}catch(FileNotFoundException ex) {
    ex.printStackTrace();
}
java.io.FileNotFoundException: adat.txt (Nincs ilyen fájl vagy könyvtár)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:211)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:153)
	at java.base/java.util.Scanner.<init>(Scanner.java:639)
	at haromszog.Haromszog.beolvas(Haromszog.java:12)
	at haromszog.Haromszog.main(Haromszog.java:35)

Csak az üzenet

App.java
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
class App {
    static Scanner scanner;
    public static void main(String args[]) throws Exception {
        try {
            File file = new File("adat.txt");
            scanner = new Scanner(file);
        }catch(FileNotFoundException ex) {
            System.err.println(ex.getMessage());
        }
    }
}

Kivétel továbbengedése

A metódus záradékában írjuk le milyen kivételeket nem szeretnénk kezelni. Ezeket a kivételeket eldobjuk.

Az IO kivételek eldobása a throws utasítással:

class Program {
    public void writeFile() throws IOException {
 
    }
}

Teljes metódus:

FileHandler.java
class FileHandler {
    public void writeFile() throws IOException {
        FileWriter fw = new FileWriter("adat.txt", true);
        fw.write("bármi\n");	
        fw.close();        
    }
}

Kivétel kezelése külön metódusban

Az eredeti writeFile() metódust átnvezem tryWriteFile() metódusra. Készítek egy writeFile() metódust, ahol kezeljük a kivételt. A tryWriteFile() metódusban csak tovább dobom a kivételt, nem kezelem.

App.java
import java.io.FileWriter;
import java.io.IOException;
 
class FileHandler {
    public void writeFile() {
        try {
            tryWriteFile();
        } catch (IOException e) {
            System.err.println("Hiba! A fájlbaírás sikertelen!");
            System.err.println(e.getMessage());
        }
    }
    public void tryWriteFile() throws IOException {
        FileWriter fw = new FileWriter("adat.txt", true);
        fw.write("bármi\n");	
        fw.close();        
    }
}
 
class App { 
    public static void main(String args[]) throws Exception {
        new FileHandler().writeFile();
    }
}

Saját kivétel készítése

Ellenőrzött kivétel készítése:

App.java
class WrongNumberException extends Exception {
    WrongNumberException(String msg) {
        super(msg);
    }
}
 
class App {
    static int kerSzam() {
        return -9;
    }
 
    public static void main(String args[]) throws Exception {
        int szam = kerSzam();
 
        if(szam<=0)
            throw new WrongNumberException("Hiba! Nem megfelelő szám!");
        else
            System.out.println("A szam: " + szam);
    }
}
App.java
class WrongNumberException extends Exception {
    WrongNumberException(String msg) {
        super(msg);
    }
}
 
class Calculate {
    private int kerSzam() {
        return -9;
    }
 
    public void calc() throws WrongNumberException {
        int szam = kerSzam();
 
        if(szam<=0)
            throw new WrongNumberException("Hiba! Nem megfelelő szám!");
        else
            System.out.println("A szam: " + szam);
    }
}
 
class App {
    public static void main(String args[]) throws Exception {
        new Calculate().calc();
    }
}
App.java
class WrongNumberException extends Exception { 
    private int num;
    WrongNumberException(int num) {
        this.num = num;
    }
    @Override
    public String toString() {
        String msg;
        if (num == 0) {
            msg = "Error! Zero number!";
        }else if(num < 0) {
            msg = "Error! Negative number!";
        }else {
            msg = "Error! Other error!";
        }
        return msg;
    }
}
 
class App {
    static int kerSzam() {
        return -9;
    }
 
    public static void main(String args[]) throws Exception {
        int szam = kerSzam();
 
        if(szam<=0)
            throw new WrongNumberException(szam);
        else
            System.out.println("A szam: " + szam);
    }
}

Ellenőrizetlen kivétel

App.java
class WrongNumberException extends RuntimeException {
    WrongNumberException(String msg) {
        super(msg);
    }
}
 
class Calculate {
    private int kerSzam() {
        return -9;
    }
 
    public void calc() {
        int szam = kerSzam();
 
        if(szam<=0)
            throw new WrongNumberException("Hiba! Nem megfelelő szám!");
        else
            System.out.println("A szam: " + szam);
    }
}
 
class App {
    public static void main(String args[]) throws Exception {
        new Calculate().calc();
    }
}

A finally blokk

A finally blokkban mondjuk meg, hogy mi az az utasítás, amelyet mindenképpen végre kell hajtani a try blokk után, még akkor is, ha a try blokk kivétellel ér véget. Jellemzően, ilyenek lehetnek az erőforrások lezárása. A következő példában egy fájt nyitunk meg írásra, és szeretnénk, ha mindenképpen le lenne zárva.

Program01.java
import java.io.FileWriter;
import java.io.IOException;
 
public class Program01 {
	public static void writeFile() {
		FileWriter fw = null;
		try {
			fw = new FileWriter("adat.txt", true);
			fw.write("alam");
		} catch(IOException ex) {
			System.err.println("Hiba a fájlbaírás során!");
		} finally {
			try {
				fw.close();
			} catch(IOException ex) {
				System.err.println("Hiba a fájl bezárása során!");
			}
		}		
	}
	public static void main (String args[]) {
		writeFile();
	}
}

A kódunk sokkal szebb, ha a kivételkezelést elválasztjuk a lényegi kódtól:

Program01.java
import java.io.FileWriter;
import java.io.IOException;
 
public class Program01 {
	public static void writeFile() {
		FileWriter fw = null;
		try {
			fw = tryFajlbaIr();
		} catch(IOException ex) {
			System.err.println("Hiba a fájlbaírás során!");
		} finally {
			try {
				fw.close();
			} catch(IOException ex) {
				System.err.println("Hiba a fájl bezárása során!");
			}
		}
	}
	public static FileWriter tryWriteFile() throws IOException {		
		FileWriter fw = new FileWriter("adat.txt", true);
		fw.write("alma");
		return fw;
	}
	public static void main (String args[]) {
		writeFile();
	}
}

A kód lényegi része a tryWriteFile() metódusban valósítható meg, így az átlátható. A hibakezeléssel pedig a writeFile() metódusban foglalkozunk.

Esetleg leválaszthatjuk a fájl megnyitását és bezárását is:

Program01.java
import java.io.FileWriter;
import java.io.IOException;
 
public class Program01 {
	public static FileWriter openFile() {
		FileWriter fw = null;
		try {
			fw = new FileWriter("adat.txt", true);
		} catch(IOException ex) {
			System.err.println("Hiba a fájl megnyitása során!");
		}
		return fw;
	}
	public static void writeFile(FileWriter fw) {
		try {
			tryWriteFile(fw);
		}catch(IOException ex) {
			System.err.println("Hiba a fájlba írás során!");
		}
	}
	public static void tryWriteFile(FileWriter fw) throws IOException {		
		fw.write("alma");		
	}
	public static void closeFile(FileWriter fw) {
		try {
			fw.close();
		} catch(IOException ex) {
			System.err.println("Hiba fájl bezárása során!");
		}
	}
	public static void main (String args[]) {
		FileWriter fw = openFile();
		writeFile(fw);
		closeFile(fw);
	}
}

Figyeljük meg a tryWriteFile() metódust, amely most sokkal átláthatóbb.

Nem megvalósított metódus

Ha egy metódust nem valósítottunk meg, akkor java.lang.UnsupportedOperationException kivételt szokás dobni:

throw new UnsupportedOperationException();

A try-with-resources szerkezet

A try() zárójelében megnyitott erőforrások automatikusan lezárásra kerülnek, függetlenül attól, hogyan záródott be; sikeresen vagy sikertelenül.

Az automatikusa lezárás csak olyan erőforrásokon lehetséges, amin alkalmazva lett a AutoCloseable vagy a Closeable interfész.

Filehanlder.java
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class Filehandler {
    public void readFile() {
        File file = new File("adat.txt");
        try(Scanner sc = new Scanner(file)){
            while(sc.hasNext()) {
                String line = sc.nextLine();
                System.out.println(line);
            }
        }catch(FileNotFoundException e) {
            System.err.println("Hiba! A fájl nem található");
            System.err.println(e.getMessage());
        }
    }
}

A kivétel tovább dobása

Filehandler.java
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
 
public class Filehandler {
    public void readFile() {
        try {
            tryReadFile();
        } catch (FileNotFoundException e) {
            System.err.println("Hiba! A fájl nem található");
            System.err.println(e.getMessage());
        }
    }
    public void tryReadFile() throws FileNotFoundException {
        File file = new File("adat.txt");
        try(Scanner sc = new Scanner(file)){
            while(sc.hasNext()) {
                String line = sc.nextLine();
                System.out.println(line);
            }
        }
    }
}

Függelék

Kivételhasználat példa

A bekért adatokat mindig ellenőrizzük le, mert lehet nem tudunk majd vele számolni, műveleteket végezni.

Legyen például egy háromszög területszámítás, ahol be kell kérnünk a háromszög alapját és magasságát. A bekérést megtehetjük a Scanner, a System vagy más osztállyal is. A buktató az lehet, ha a felhasználó nem számot ír, vagy nem jó formában írja.

A következő kód egy háromszög alapjának bekérése System osztállyal:

System.out.print("Alap: ");
String alapStr = System.console().readLine();
int alap = Integer.parseInt(alapStr);

Ez mindaddig jól működik, amíg a felhasználó számot ír. Ha felhasználó nem egész számot ír be, akkor a program kivételt dob. A fordítás kimenetében látszik, hogy a kivétel neve „NumberFormatException”. Ebből tudhatjuk, hogy ezt kell kezelnünk.

A kivétel kezelése:

System.out.print("Alap: ");		
String alapStr = System.console().readLine();
int alap;
try{
	alap = Integer.parseInt(alapStr);
}catch(NumberFormatException ex){
	System.err.println("Csak egész szám adható meg!");
}

Az alap bekérése kezd egészen sok sorból állni. Célszerű külön függvénybe tenni:

Program01.java
class Program01
{
	private static int beAlap(){
		int alap=0;
		boolean szamOk = false;
		do{
			System.out.print("Alap: ");		
			String alapStr = System.console().readLine();			
			try{
				alap = Integer.parseInt(alapStr);
				szamOk = true;
			}catch(NumberFormatException ex){
				System.err.println("Számot kértem!");
			}			
		}while(!szamOk);
		return alap;
	}	
	public static void main(String args[])
	{
		int alap = beAlap();
	}
}

Viszont ha a másik számot is ugyanígy kérjük be, akkor általánosíthatjuk a függvényünket:

Program01.java
class Program01
{
	private static int beEgeszSzam(String bekerFelirat){
		int szam=0;
		boolean szamOk = false;
		do{
			System.out.print(bekerFelirat);		
			String szamStr = System.console().readLine();			
			try{
				szam = Integer.parseInt(szamStr);
				szamOk = true;
			}catch(NumberFormatException ex){
				System.err.println("Egész számot kértem!");
			}			
		}while(!szamOk);
		return szam;
	}	
	public static void main(String args[])
	{
		int alap = beEgeszSzam("Alap: ");
		int magassag = beEgeszSzam("Magasság: ");
	}
}

A végleges változat:

Program01.java
class TulKisSzamException extends Exception 
{ 
	TulKisSzamException(String uzenet)
	{
		super(uzenet);
	}
}
 
class Haromszog {
	public static double beValosSzam(String bekerFelirat){
		double valosSzam=0;
		boolean szamOk = false;
		do{
			System.out.print(bekerFelirat);		
			String szamStr = System.console().readLine();			
			try{
				valosSzam = Double.parseDouble(szamStr);
				szamOk = true;
			}catch(NumberFormatException ex){
				System.err.println("Valós számot kértem!");
			}			
		}while(!szamOk);
		return valosSzam;
	}
	public static double szamolTerulet(double alap, double magassag) 
					throws TulKisSzamException{
		if(alap<1 || magassag<1){
			throw new TulKisSzamException("Túl kis szám");
		}		
 
		double terulet = 0;		
		terulet = (alap * magassag) / 2.0;
		return terulet;
	}
}
 
class Program01 {
 
	private static double  trySzamol(double alap, double magassag){
		Haromszog haromszog = new Haromszog();
		double terulet = 0;
		try {
			terulet = haromszog.szamolTerulet(alap, magassag);
		}catch(TulKisSzamException ex){
			System.err.println("Túl kis szám!");
		}
		return terulet;
	}
	public static void main(String args[]){
		Haromszog haromszog = new Haromszog();
		double alap = haromszog.beValosSzam("Alap: ");
		double magassag = haromszog.beValosSzam("Magasság: ");
		double terulet = trySzamol(alap, magassag);
		System.out.printf("Terület: %.2f\n", terulet);
	}
}
oktatas/programozas/java/java_kivetelek.txt · Utolsó módosítás: 2024/02/05 11:17 szerkesztette: admin