본문 바로가기

프로그래밍/Java

Java_예외처리(2)_멀티 catch블럭, 예외 발생시키기, 체크드예외와 언체크드예외, 메서드에 예외 선언하기, finally블럭

- 멀티 catch블럭

: 내용이 같은 catch블럭을 '|'기호를 이용해 하나로 합친 것. 

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

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

→ 조상과 자손의 관계에 있다면 컴파일 에러가 발생한다. 

: 그냥 조상 클래스만 써주는 것과 똑같기 때문에 불필요한 코드는 제거하라는 뜻에서 에러가 발생하는 것이다. 

 

try {
    ...
} catch (ExceptionA | ExceptionB e) {
    e.methodA(); // 에러. ExceptionA에 선언된 methodA()는 호출 불가.
    
    if(e instanceof ExceptionA) {
    	ExceptionA e1=(Exception)e;
        e1.methodA();
    } else {
    	...

→ 멀티 catch는 하나의 catch블럭으로 여러 예외를 처리하기 때문에, 발생한 예외를 멀티 catch블럭으로 처리하게 되었을 때, 멀티 catch블럭 내에서는 실제로 어떤 예외가 발생한 것인지 알 수 없다.

그래서 ExceptionA와 ExceptionB의 공통멤버만 사용이 가능하다. 

 

 

 

- 예외 발생시키기 

: 키워드 throw를 사용해서 고의로 예외를 발생시킨다. 

class JavaJungsuk_basic_Exception_Ex8_6 {
    public static void main(String[] args) {
    	try {
            Exception e=new Exception("고의로 발생시킴.");
        } catch (Exception e) {
            System.out.println("에러 메시지: "+e.getMessage());
            e.printStackTrace();
        }
        System.out.println("프로그램이 정상 종료되었음.");
    }
}

결과
에러 메시지: 고의로 발생시킴.
java.lang.Exception: 고의로 발생시킴.
	at JavaJungsuk_basic_Exception_Ex8_6.main(JavaJungsuk_basic_Exception_Ex8_6.java:4)
프로그램이 정상 종료되었음.

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

 

 

 

- 체크드 예외(checked Exception)와 언체크드 예외(unchecked Exception)

class JavaJungsuk_basic_Exception_Ex8_7 {
    public static void main(String[] args) {
    	throw new Exception();
    }
}
결과
JavaJungsuk_basic_Exception_Ex8_7.java:3: unreported exception java.lang.Exception; must be caught or declared to be thrown
		throw new Exception();
^
1 error

 

→ 체크드 예외 : 컴파일러가 예외 처리 여부를 체크 (예외 처리 필수) > Exception과 자손들, try-catch 필수 !

 

class JavaJungsuk_basic_Exception_Ex8_8 {
    public static void main(String[] args){
    	throw new RuntimeException();
    }
}
결과
Exception in thread "main" java.lang.RuntimeException
		at JavaJungsuk_basic_Exception_Ex8_8.main(JavaJungsuk_basic_Exception_Ex8_8.java:3)

 

→ 언체크드 예외 : 컴파일러가 예외 처리 여부를 체크 안함. (예외처리 선택) > RuntimeException과 자손들, try-catch 선택

 

 

 

- 메서드에 예외 선언하기

: 메서드가 호출 시 발생가능한 예외를 호출하는 쪽에 알리는 것. 

메서드의 선언부에 키워드 throws를 사용해서 메서드 내에서 발생할 수 있는 예외를 적어주면 된다. 

class JavaJungsuk_basic_Exception_Ex8_9 {	//try-catch문 필요
    public static void main(String[] args) throws Exception {
    	method1();
    }
    
    static void method1() throws Exception {
    	method2();
    }
    
    static void method2() throws Exception {
        throw new Exception();
    }
}

결과
Exception in thread "main" java.lang.Exception
    at JavaJungsuk_basic_Exception_Ex8_9.method2(JavaJungsuk_basic_Exception_Ex8_9.java:11)
    at JavaJungsuk_basic_Exception_Ex8_9.method1(JavaJungsuk_basic_Exception_Ex8_9.java:7)
    at JavaJungsuk_basic_Exception_Ex8_9.main(JavaJungsuk_basic_Exception_Ex8_9.java:3)

→ 실행결과를 보면 예외가 발생한 곳은 제일 윗줄에 있는 method2();라는 것과 main메서드 -> method1()을, method1()은 method2()를 호출하여 비정상 종료가 되었다는 것을 알 수 있다. 

 

→ 예외가 선언되어 있으면 Exception과 같은 체크드 예외를 try-catch문으로 처리하지 않아도 컴파일 에러가 발생하지 않는다. 

 

 

- finally블럭

: 예외 발생여부와 관계없이 수행되어야 하는 코드를 넣는다. 

try {
    //예외가 발생할 가능성이 있는 문장들을 넣는다. 
} catch (Exception1 e1) {
    //예외처리를 위한 문장을 적는다. 
} finally {
    //예외의 발생여부에 관계없이 항상 수행되어야 하는 문장들을 넣는다.
    //finally블럭은 try-catch문의 맨 마지막에 위치해야한다. 
}

 

try {
    startInstall();
    copyFiles();
    deleteTempFiles();	//중복.
} catch(Exception e) {
    e.printStackTrace();
    deleteTempFiles();	//중복.
}

↓
try {
    startInstall();
    copyFiles();
} catch(Exception e) {
    e.printStackTrace();
} finally {
    deleteTempFiles();	//코드중복제거
}

→ 위 코드에서 보이는 것처럼 try블럭과 catch블럭에 같은 코드를 넣기보다는 finally 블럭에 넣어 중복을 제거할 수 있다.