반응형

예외를 처리하는 방법에는 try-catch문 이외에도 더 있다.
바로, 예외선언하기, 은폐 이다. 

try-catch문은 예외를 직접 처리하는 것이라고 볼 수 있고,

예외 선언하기는 예외 떠넘기기라고 볼 수 있다.

은폐는 try-catch문을 사용하는데, 빈 catch블럭을 사용하는 것이다.

 

메서드에 예외 선언하기

  • 예외를 처리하는 방법 : try-catch문, 예외 선언하기
  • 메서드가 호출시 발생가능한 예외를 호출하는 쪽에 알리는 것

 

예외 선언하기는 실제로는 예외를 처리하는 것이 아니라. 예외 떠넘기기 이다. (알리기)

예외를 자기가 처리하는 것이아니라.
자기를 호출한 사람한테 예외처리를 떠넘기는 것이다.

즉, 예외를 호출한 쪽에 알리는 것이다.

예외선언하는 방법을 알아보자.

method() 다음에 throws라는 키워드를 사용하고, 이 메서드를 호출했을 때, 발생할 수 있는 예외들을 콤마를 구분자로하여 적는다.

※ 예외를 발생시키는 키워드 throw와 예외를 메서드에 선언할 때 쓰이는 throws를 잘 구별하자.

 

두번째 메서드는, 메서드가 떠넘길수 있는 예외가 모든 예외의 최고조상인 Exception이다.
즉, 모든 종류의 예외가 발생가능하다는 것이다.

오버라이딩 조건 3가지
- 선언부 일치
- 접근 제어자 좁게X
- 조상보다 많은 예외선언X

 

위예제를 보면, 겉으로 보기엔, 첫번째 메서드가 발생할 수 있는 예외 3가지, 두번째 메서드는 3가지로
첫번째가 많아보이지만,

실제로는, Exception이 모든 예외의 최고조상이기 때문에, 범위가 훨씬 넓기 때문에 두번쨰 메서드가 포함하고 있는 예외의 갯수가 훨씬 많다. 

 

예제를 보자.

작업을 진행하는 startInstall메서드인데, 
작업을 진행하다가 공간이 부족하면, 공간이 부족하다는 예외를 발생시켜서 자신을 호출한 메서드한테 알려주는 것이다.
그리고, 메모리가 부족하면 메모리가 부족하다고 자신을 호출한 메서드한테 알려준다. 

본인이 처리할 수 있는 일은 처리하지만, 본인이 처리할 수 없는 일은 처리하지만,
본인이 처리할 수 없는 메시지는 본인이 처리하지 않고, 자신을 호출한 메서드한테 알려준다. 

이것을 메서드에 예외 선언하기 이다. 

즉, startInstall이라는 메서드를 호출하면, SpaceException과 MemoryException이라는 두가지 예외가 발생할 수 있다는 것을 적어놓은 것이다. 

그러면, startInstall을 사용하는 쪽에서는 앞서 기재해둔 두가지 예외에 대한 try-catch문이 필요할 것이다. 
아니면, 자기도 자신을 호출한 메서드에게 떠넘길 수도 있을 것이다.

 

 

JavaAPI문서에서 wait이라는 메서드를 찾아본 것이다. 
그래서, 해당 메서드에 대한 설명과 선언부를 볼 수 있다.
Throws라는 부분을 보면, wait를 호출했을 때,
IllegalMonitorStateException, InterruptedException 2가지가 발생할 수 있다고 써있다.

즉, wait메서드를 사용할 때는 기재되어있는 2가지 예외처리를 해줘야 한다.

그런데, 선언부를 보면,InterruptedException만 선언되어 있다.
왜 발생할 수 있는 예외가 2갠데, 왜 1개만 적었을까?

그 이유는, 바로 IllegalMonitorStateExceptionRuntimeException의 자손이어서 그렇다.
RuntimeException은 Unchecked 예외이기 때문에 예외처리 선택이다.

InterruptedException는 Exception의 자손이다. 즉 예외처리 필수다.

결국, 선언부에는 필수처리 예외만 선언한다.(checked예외)

 

[Ex8_9]

main메서드가 method1을 호출하고,
method1이 method2를 호출하고, 
method2에서 예외가 발생했다.

이것을 호출스택으로 그림을 그려보면 아래와 같다.

main에서 method1을 호출했고, 
method1에서 method2를 호출했다. 
그런데, method2에서 예외가 발생했는데,  try-catch문이 없어서 예외처리를 할 수 없다 .
그래서 예외처리를 하지 못하고 method2는 죽으면서, 해당 예외를 자신을 호추한 method1에게 떠넘긴다. 
그러면 method1에서 예외가 발생한 셈이 된다. 
그런데, method1에도 try-catch가 없다.
따라서 method1도 예외를 처리하지못하고 method1이 죽으면서 예외를 자신을 호출한 main메서드에게 넘긴다.
결국, main메서드가 예외를 받게 되었는데, 
main메서드에도 try-catch가 없다.
대신에 자신도 예외를 떠넘기는데, main메서드가 죽으면서 비정상 종료되면서 예외를 JVM에게 넘겨준다. 
JVM이 최종적으로 예외를 처리하는데, JVM의 기본 예외처리기가 출력한 내용이다. (printStackTrace로 출력했을 것이다.)

해당 예외메시지에는 어떠한 정보가 담겨있을까?

method2에서 예외가 발생한 당시의 호출스택의 상황을 그대로 담고있다. 

즉, 선언은 자신을 호출한 것에게 예외를 떠넘기는 것이지, 예외를 처리하는게 아니다.
실제로 처리되려면 try-catch문이 있어야 한다.

예외를 처리하는 것(try-catch블럭)
예외를 떠넘기는 것(메서드에 예외 선언) 
의 차이를 잘 알아두자.

 

 

예제를 보자.

해당 코드를 실행할 떄, test2.txt라는 파일을 지정해주면, 
args[0]에 "text2.txt"이 문자열로 들어오고,
text2.txt라는 이름으로 파일을 생성한다.

main에서 createFile메서드를 호출했다. 
createFile메서드의 매개변수에 "test2.txt"가 넘어왔다.
이 이름을 체크하는데,
이름이 null인지 확인하고, ""(빈문자열)인지 확인해서 
null이나 빈문자열이면 메서드를 발생시키는 throw를 이용해서  Exception예외를 생성해서 던진다.

 

결과의 입력을 기준으로,

만약에 fileName이 null이나 빈문자열이 아니면,
fileName을 제목으로 파일객체를 만들고, 해당 객체의 주소를 저장한 참조변수를 반환한다.

만약에 filename으로 ""(빈문자열)을 주면, 파일이름이 유효하지 않습니다.라는 Exception예외가 생성된다.
그러면 해당 예외가 createFile메서드를 호출한 main메서드로 던져지게 된다.
처리하지 못한 예외를 main메서드로 던졌고, 
해당 예외는 main메서드에서 발생한 것이된다.

try문의 File f = createFile(args[0]); 에서 예외가 발생한 것이다.
그후, 해당 예외를 처리할 수 있는 catch블럭이 있는지 찾게된다.

위 예제의 결과에 있는 있는 ""을  ceate메서드에서 발생된 예외는 Exception인데, 
main메서드의 catch블럭에 Exception e는 모든 예외를 처리할 수 있으므로 해당 catch블럭에서 예외가 처리된다.
"다시 입력해 주시기 바랍니다."라고 메시지를 출력한다.

 

예외가 발생했을 때는, 
1. 예외를 직접 처리할 것인지,
2. 떠넘길 것인지(알릴 것인지)
를 결정해서

1.번의 경우에는 try-catch문을 이용해서 바로 처리하고,
2.번의 경우에는 thorws를 이용해서 예외를 떠념겨서 던진다.

 

예외가 생성되면, 해당 예외는, 작업을 시킨 메서드가 처리하는 것이 맞는 것인지, 
작업을 수행하는 메서드가 처리하는 것이 맞는 것인지에 따라서 try-catch블럭을 어디에 넣을지 결정하면 된다. 

 


 

finally 블럭

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

 

finally블럭은, 예외가 발생하던, 발생하지 않던 수행되어야 하는 코드를 넣는 블럭을 말한다.

 

위의 코드를 보면, 지금까지 try-catch블럭만 있었던 것과 달리, finally블럭이 있다.

finally블럭 안에 있는 문장들은 예외 발생여부와 관계없이 항상 수행된다.

fnally블럭은 try-catch문의 맨 마지막에 위치해야 한다.

※ try블럭 안에 return문이 있어서 try블럭을 벗어나갈 때도 finally블럭이 실행된다.

 

예제를 보자.

startinstall()하고,
copyFiles()를 하고나면,
deleteTempFiles()로 임시파일을 삭제해야 한다.

그런데, 설치하다가 예외가 발생해서 catch블럭으로 가도 임시파일 삭제를 해야한다.

즉, 설치를 잘 마쳐서 파일을 복사하고 난 뒤에도 임시파일을 삭제해야 하고,
설치하다가 예외가 발생해도 임시파일을 삭제해야 한다.

그런데 try문과 catch문에 각각 deleteTempFiles()를 적게되면 코드의 중복이 발생한다.

그래서 이 중복을 제거하기 위해 나온 것이 finally블럭이다.

예외가 발생하건, 발생하지 않건 수행하는 코드를 finally블럭에 작성한다. 
그러면, 코드의 중복을 제거하면서 필요한 코드를 수행시킬 수 있다.

반응형