본문 바로가기
자바/Java의 정석

[Chapter 08] 예외처리

by 코딩diary 2024. 11. 23.

프로그램 오류

컴파일 에러 - 컴파일 시에 발생하는 에러

런타임 에러 - 실행 시에 발생하는 에러

논리적 에러 - 실행은 되지만, 의도와 다르게 동작하는 것

 

에러 - 프로그램 코드에 의해서 수습될 수 없는 심각한 오류

예외 - 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류

 

 

예외처리하기 try-catch 문

예외처리의

정의 : 프로그램 실행 시 발생할 수 있는 예외에 대비한 코드를 작성하는 것

목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

try { 
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
	// Exception1이 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
} catch (Exception2 e2) {
	// Exception2가 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
} catch (ExceptionN eN) {
	// ExceptionN이 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
}

 

public class ExceptionEx {
    public static void main(String[] args) {
        int number = 100;
        int result = 0;

        for (int i = 0; i < 10; i++) {
            result = number / (int)(Math.random() * 10);
            System.out.println(result);
        }
    }
}

/*
	0으로 나눌 때 ArithmeticException 에러 발생
*/

0으로 나눌 때 위 코드에 에외 발생으로 프로그램이 비정상적으로 종료된다.

public class ExceptionEx2 {
    public static void main(String[] args) {
        int number = 100;
        int result = 0;

        for (int i = 0; i < 10; i++) {
            try {
                result = number / (int) (Math.random() * 10);
                System.out.println(result);
            } catch (ArithmeticException e) {
                System.out.println("0");		// ArithmeticException이 발생하면 실행
            }
        }
    }
}

이렇게 하면 ArithmeticException이 발생할 때 0을 출력하고 예외가 발생하여 프로그램이 비정상적으로 종료되지 않는다.

 

try 블럭 내에서 예외가 발생한 경우,

1. 발생한 예외와 일치하는 catch 블럭이 있는지 확인.

2. 일치하는 catch 블럭 찾으면 그 블럭 내 문장을 수행하고 try-catch문을 빠져나가서 다음 문장을 계속해서 수행. 만일 일치하는 catch 블럭을 찾지 못하면 예외는 처리되지 못한다.

 

try 블럭 내에서 예외가 발생하지 않은 경우,

1. catch 블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다.

public class ExceptionEx3 {
    public static void main(String[] args) {
        System.out.println(1);
        System.out.println(2);
        try {
            System.out.println(3);
            System.out.println(0/0);	// 0을 나눠서 고의로 ArithmeticException 발생
            System.out.println(4);	// 실행되지 않는다
        } catch (ArithmeticException e) {
            System.out.println(5);
        }
        System.out.println(6);
    }
}

위 코드의 catch (ArithmeticException e) 대신 catch (Exception e)를 사용해도 결과는 같다. 이유는 ArithmeticException 클래스는 Exception 클래스의 자손이므로 ArithmeticException 인스턴스와 Exception 클래스와의 instanceof 연산결과가 true가 되기 때문이다.

 

 

printStackTrace() - 예외발생 당시의 호출스택에 있었던 메서드의 정보와 예외 메서드를 화면에 출력한다.

getMessage() - 발생한 예외클래스의 인스턴스에 저장된 메세지를 얻을 수 있다.

public class ExceptionEx4 {
    public static void main(String[] args) {
        System.out.println(1);
        System.out.println(2);
        try {
            System.out.println(3);
            System.out.println(0/0);
            System.out.println(4);
        } catch (ArithmeticException ae) {
            ae.printStackTrace();
            System.out.println("에외메세지 : " + ae.getMessage());
        }
        System.out.println(6);
    }
}

/*
1
2
3
에외메세지 : / by zero
6
java.lang.ArithmeticException: / by zero
	at ExceptionEx4.main(ExceptionEx4.java:7)
*/

 

 

멀티 catch블럭

try {
	...
} catch (ExceptionA e) {
	e.printStackTrace();
} catch (ExceptionB e2) {
	e2.printStackTrace();
}

// '|' 기호로 하나의 catch블럭으로 합침

try {
	...
} catch (ExceptionA | ExceptionB e) {
	e.printStackTrace();
}

 

 

예외 발생시키기

키워드 throw를 사용해서 고의로 예외를 발생시킬 수 있다.

 

1. 먼저, 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든 다음

Exception e = new Exception("고의로 발생시켰음");

 

2. 키워드 throw를 이용해서 예외를 발생시킨다.

throw e;

class ExceptionEx9 {
	public static void main(String[] args) {
    	try {
        	Exception e = new Exception("고의로 발생시켰음.");
            	throw e;	// 예외 발생
            	// throw new Exception("고의로 발생시켰음.);  <- 위 두줄을 한줄로 표현
        } catch (Exception e)
            System.out.println("에러 메시지 : " + e.getMessage());
            e.printStackTrace();
        }
        System.out.println("프로그램이 정상 종료되었음");
    }
}

 

 

RuntimeException 고의로 발생

calss ExceptionEx11 {
	public static void main(String[] args) {
    	throw new RuntimeException(); // RuntimeException 고의로 발생
    }
}

 

 

메서드에 예외 선언하기

void method() throws Exception1, Exception2, ... , ExceptionN {
	// 메서드 내용
}

 

 

finally 블럭

예외의 발생여부에 상관없이 실행되어야할 코드를 포함시킬 목적으로 사용.

try-catch-finally 순서로 구성

try {
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
	// 예외처리를 위한 문장을 적는다.
} finally {
	// 예외의 발생여부에 관계없이 항상 수행되어야하는 문장들을 넣는다.
	// finally 블럭은 try-catch문의 맨 마지막에 위치해야한다.
}
class FinallyTest2 {
	public static void main(String[] args) {
    	try {
        	startInstall();
            copyFiles();
        } catch (Exception e) {
        	e.printStackTrace();
        } finally {
        	deleteTempFiles();
        }
    }
    
    static void startInstall() {
    	// 프로그램 설치에 필요한 준비를 하는 코드를 적는다.
    }
    static void copyFiles() { // 파일들을 복사하는 코드를 적는다. }
    static void deleteTempFiles() { // 임시파일들을 삭제하는 코드를 적는다. }
}