본문 바로가기

Java

Java- 예외처리

예외처리

 try ~ catch

  일반적인 예외처리처럼 try catch구문을 통해서 예외처리를 진행한다.

import java.util.Scanner;

public class DivideByZero {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        try{
            int a = sc.nextInt();
            int b = sc.nextInt();  //b = 0;

            System.out.printf("%d / %d = %d",a,b,a/b);
        }
        catch (ArithmeticException e){
            e.printStackTrace();
        }
    }
}

a>>>1
b>>>0
java.lang.ArithmeticException: / by zero
	at DivideByZero.main(DivideByZero.java:13)

  여기서는 정수를 0으로 나누어 ArithmeticException 에러가 발생하였다. 예외 클래스는 그 수가 굉장히 많기 때문에 그걸 다 외우는 것은 무리다. 

  그렇기에 찾아보면서 하는게 낫다. 참고로 최상위 에러 클래스는 Throwable이다. 그리고 이들은 또 크게 3부류의 에러 클래스가 Throwable을 상속한다.

 

  1. Error 클래스를 상속하는 예외 클래스
  2. Exception 클래스를 상속하는 예외 클래스
  3. RuntimeException 클래스를 상속하는 예외 클래스 (RuntimeException은 Exception을 상속한다)

 Exception 클래스

  Error와 RuntimeException은 예외처리가 필수는 아니지만, Exception 클래스의 경우 예외처리는 필수적이다.

Exception 클래스를 상속받는 클래스(그러나 RuntimeException은 상속받지 않는)들의 경우

필수적으로 try~catch로 예외처리를 해주거나 아니면 throws 키워드를 통해서 예외처리를 넘겨주어야 한다.

  • ErrorRuntimeException나 이들을 상속하는 클래스는 예외처리를 반드시 할 필요는 없음.
  • Exception 관련 클래스는 반드시 예외처리 필요.

 

  throws 키워드

  throws 키워드는 메소드 A에서 에러가 발생했을 때, A의 예외처리를 A에서 진행하지 않고, A를 호출한

메소드 B에게 예외처리를 넘긴다.

 만일 main에 throws를 사용한다면 자바 가상머신에게 예외처리를 넘기고 그 프로그램은 종료된다.

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class ExtendsExceptionClass {
    //Exception 클래스를 상속받는 IOException 클래스
    public static void main(String[] args) {
        try{
            md1();
        }
        catch(IOException e){  //IOException 예외처리
            e.printStackTrace();
            System.out.println("error occur");
        }
    }
    //throw 키워드로 예외 처리를 해당 메소드를 호출한 다른 메소드로 넘길 수 있다.
    public static void md1() throws IOException{  //IOExceoption 발생시 md1()을 호출한 메소드(main)로 예외처리를 넘김
        md2(); //md2()를 호출하는 메소드
    }
    public static void md2() throws IOException{  //IOException이 발생시 md2()를 호출한 메소드(md1)로 예외처리를 넘김
        Path file = Paths.get("C:\\JavaStudy\\Simple.txt");
        BufferedWriter writer = null;
        writer = Files.newBufferedWriter(file);  //IOException 발생가능
        writer.write('A');  //IOException 발생가능
        writer.write('Z');  //IOException 발생가능

        if(writer != null)
            writer.close();
    }
}


java.nio.file.NoSuchFileException: C:\JavaStudy\Simple.txt  //NoSuchFileException extends IOException
	at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
	at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
	at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
	at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:230)
	at java.nio.file.spi.FileSystemProvider.newOutputStream(FileSystemProvider.java:434)
	at java.nio.file.Files.newOutputStream(Files.java:216)
	at java.nio.file.Files.newBufferedWriter(Files.java:2860)
	at java.nio.file.Files.newBufferedWriter(Files.java:2896)
	at ExtendsExceptionClass.md2(ExtendsExceptionClass.java:25)
	at ExtendsExceptionClass.md1(ExtendsExceptionClass.java:20)
	at ExtendsExceptionClass.main(ExtendsExceptionClass.java:11)
error occur

//예외처리 과정

// main에서 md1()호출 -> md2()호출 -> md2()에서 IOException 발생 ->
// 예외처리를 md1()으로 넘김 -> 예외처리를 main으로 넘김 -> main에서 예외처리

 일단 설명을 하자면 IOException 클래스 에러는 Exception 클래스를 상속받는다.

위 코드의 함수 호출과정은 다음과 같다. (main -> md1 -> md2).  그리고 md2에서 IOException에러가 발생한다. 

에러의 throws는 md2 -> md1 -> main순으로 전달되어 main에서 try~catch를 통해서 예외처리가 진행된다.

 

 md1과 md2를 보면 메소드 뒤에 throws IOException이 붙어있는 것을 볼 수있다. 이는 해당 메소드에서 IOException 관련 에러가 발생시 해당 메소드를 호출한 메소드로 예외처리를 넘긴다는 말이다. 

 

사용자 정의 예외처리

  기존의 에러 클래스들 처럼 나도 에러클래스를 만들어서 사용할 수 있다. 다음 예에선 Exception 클래스를 상속받는 ReadAgeError 에러 클래스를 정의한다. 메소드 readAge()에서 ReadAgeError가 발생하고 해당 예외처리를

main에서 해주는 식이다. 

import java.util.Scanner;

class ReadAgeException extends Exception{  // 사용자 정의 에러 클래스 (Exception 클래스 상속)
    ReadAgeException(){
        super("error!! 유효하지 않은 나이가 입력되었습니다.");
        //Exception의 생성자 호출및 에러 메시지 초기화
        //해당 메시지는 public String getMessage() 호출시 메시지 반환
    }
}
public class MyExceptionClass {
    public static void main(String[] args) {
        try{
            int age = readAge();
            System.out.printf("나이는 %d살입니다",age);
        }
        catch(ReadAgeException e){
            System.out.print(e.getMessage());
            //Exception의 생성
        }
    }
    
    public static int readAge() throws ReadAgeException{
        Scanner sc = new Scanner(System.in);
        System.out.print("나이 입력>>>");
        int age = sc.nextInt();

        if(age<0)
            throw new ReadAgeException();  
            //ReadAgeException 인스턴스 생성 후 던짐
        
        return age;
    }
}


나이 입력>>>-123
error!! 유효하지 않은 나이가 입력되었습니다.

  사용자 정의 에러 클래스 ReadAgeException을 보면 Exception을 상속받고 있다. 그리고 ReadAgeException의 생성자에선 Exception의 생성자를 호출 후, 에러 상황에 대한 메시지를 전달하고 있다. 

 해당 에러 메시지는 Throwable 클래스에 정의된 Public String getMessage(); 호출 시 반환된다. 그래서 여기선 Exception을 상속받긴 했지만 상위 클래스의 Throwable을 상속해도 실행은 똑같이 된다.

'Java' 카테고리의 다른 글

Java- 래퍼 클래스  (0) 2023.01.03
Java- Object 클래스  (0) 2023.01.02
Java- 인터페이스와 추상클래스 비교  (0) 2023.01.01
Java- interface  (0) 2022.12.30
Java- Object 클래스  (0) 2022.12.29