[Chap 14] 14. 예외 처리
예외 처리하기
try-catch문
try 블록에는 예외가 발생할 가능성이 있는 코드를 작성한다. 만약에 예외가 발생한다면 바로 catch문 블록이 수행된다.
try {
(예외가 발생할 수 있는 코드 부분)
} catch (처리할 예외 타입 e) {
try 블록 안에서 예외가 발생했을 때의 예외를 처리하는 부분
}
try-catch문 사용하기
package exception;
public class ArrayExceptionHandling {
public static void main(String[] args) {
int[] arr = new int[5];
try {
for (int i = 0; i <= 5; i++) {
arr[i] = i;
System.out.println(arr[i]);
}
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println(e);
System.out.println("예외 처리 부분");
}
System.out.println("프로그램 종료");
}
}
>>>출력문
0
1
2
3
4
java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
예외 처리 부분
프로그램 종료
배열에 들어갈 수 있는 인덱스의 크기는 0~4인데 인덱스 값에 5가 들어가면 ArrayIndexOutOfBoundsException 에러가 발생한다. 그래서 i == 5이면 catch문으로 넘어가서 예외 처리 부분으로 넘어간 후, 프로그램을 정상 종료시켰음을 볼 수 있다.
컴파일러에 의해 예외가 체크되는 경우
파일 입출력에서 발생하는 예외 처리하기
FileInputStream fis = new FileInputStream("a.txt");
라는 코드는 파일에서 데이터를 바이트 단위로 읽어 들이는 FileInputStream을 사용하여, a.txt 파일에서 데이터를 읽어들이기 위한 객체 fis를 생성한다.
package exception;
import java.io.FileInputStream;
public class ArrayExceptionHandling2 {
public static void main(String[] args) {
FileInputStream fis = new FileInputStream("a.txt");
}
}
이 코드를 보면 new FileInputStream(“a.txt”); 부분에서 FileNotFoundException 이라는 에러가 나왔다. 즉, a.txt 라는 파일을 찾을 수 없다는 에러이다. 읽으려는 파일이 없는 경우에 자바 가상 머신에서는 FileNotFoundException 예외 클래스가 생성된다. 따라서 우리는 이런 예외를 처리해주기 위해서 try-catch문으로 감사주어야 한다.
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ArrayExceptionHandling2 {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("a.txt");
} catch (FileNotFoundException e){
System.out.println(e);
}
System.out.println("여기도 수행됩니다.");
}
}
>>>출력값
java.io.FileNotFoundException: a.txt (지정된 파일을 찾을 수 없습니다)
여기도 수행됩니다.
a.txt라는 파일이 없으므로 FileNotFoundException 이라는 예외 클래스가 생성되었다. 그렇기 때문에 catch문으로 들어가서 에러 사항을 출력하고 정상 종료되었음을 확인할 수 있다.
try-catch-finally문
try-catch문에서는 파일을 열어주는 객체를 사용하고 닫지 않고 계속 사용할 경우에는 시스템에서 허용하는 자원의 한계가 있기 때문에 close() 메서드를 사용해서 닫아주어야 한다. 하지만 close() 메서드는 try문으로 가든, catch문으로 가든 무조건 닫아야 되는 것이므로 이때 finally문을 사용한다.
try {
(예외가 발생할 수 있는 코드 부분)
} catch (처리할 예외 타입 e) {
try 블록 안에서 예외가 발생했을 때의 예외를 처리하는 부분
} finally {
(항상 수행되는 부분)
}
try-catch-finally문 사용하기
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionHandling3 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("a.txt");
} catch (FileNotFoundException e) {
System.out.println(e);
return; //-> 예외가 발생한다면 강제로 return 하도록 하기 위해 넣음
} finally {
if (fis != null) {
try {
fis.close(); //파일 입력 시트림 닫기
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("항상 수행됩니다.");
}
System.out.println("여기도 수행됩니다.");
}
}
>>>출력값
java.io.FileNotFoundException: a.txt (지정된 파일을 찾을 수 없습니다)
항상 수행됩니다.
코드를 설명하자면 try-catch-finally문이 가장 바깥에 있고, finally문에 작은 try-catch문이 있습니다. 바깥에 있는 예외 처리문은 읽을 파일이 있는지, 없는지에 따라 catch문의 수행여부가 결정됩니다. 여기서 예외가 발생한다면 에러 종류를 출력하고, 강제로 return을 합니다. 하지만 여기서 “항상 수행됩니다.”가 출력됨을 확인할 수 있습니다. 즉, finally문같은 경우는 try문, catch문 모두 실행됨을 확인할 수 있습니다.(catch문의 리턴보다 먼저 실행)
try-with-resources문
자바7부터는 close() 메서드를 명시적으로 호출하지 낳아도 try 블록내에서 열린 리소스를 자동으로 닫도록 만들 수 있다. 이를 사용하기 위해서는 AutoCloseable 인터페이스를 구현해야 한다. AutoCloseable
인터페이스에는 close() 메서드 부분이 있고, 이를 구현한 클래스 close()를 명시적으로 호출하지 않아도 close() 메서드 부분이 호출된다.
try-with-resources문 사용하기
//AutoCloseObj.java
package exception;
public class AutoCloseObj implements AutoCloseable{
@Override
public void close() throws Exception {
System.out.println("리소스가 close() 되었습니다.");
}
}
//AutoCloseObjTest.java
package exception;
public class AutoCloseTest {
public static void main(String[] args) {
try (AutoCloseObj obj = new AutoCloseObj()) {
} catch(Exception e) {
System.out.println("예외 부분입니다. ");
}
}
}
>>> 출력값
리소스가 close() 되었습니다.
객체를 만드는 것은 에러가 발생하지 않는 사항이므로 바로 리소스를 close했다. 여기서 AutoCloseObj라는 객체는 AutoCloseable이라는 인터페이스를 상속받았으므로 따로 리소스를 닫아주지 않아도 자동으로 닫힌것이다. 그럼 예외처리를 하면 어떻게 될까?
package exception;
public class AutoCloseTest {
public static void main(String[] args) {
try (AutoCloseObj obj = new AutoCloseObj()) {
throw new Exception();
} catch(Exception e) {
System.out.println("예외 부분입니다. ");
}
}
}
>>> 출력값
리소스가 close() 되었습니다.
예외 부분입니다.
예외 처리를 하기 위해서는 throw 라는 예약어가 사용된다. 예외로 처리되었는데도 자동으로 리소스가 닫힌 것을 확인할 수 있다.
댓글남기기