※ 위의 두개의 목적을 이루기 위해 예외처리는 필수적으로 해줘야한다.
로그는 기업마다 로그를 남기는 format이 따로 있다.
Throwable class : 모든 예외처리 클래스의 조상이 되는 클래스로 Throwable 타입과 이 클래스를 상속받은 서브 타입만이 JVM이나 throw키워드에 의해 던져질 수 있다.
Error class : 동적 메모리가 없는 경우, 스택 메모리의 오버플로우 등 가상 머신에서 발생하는 프로그래머가 처리할 수 없는 오류이다.
Exception class : 읽으려는 파일이 존재하지 않거나 네트워크나 DB연결이 안되는 경우 등의 프로그램에서 제어할 수 있는 오류이며 모든 예외에 대한 catch가 가능하다.
자바는 안전성이 중요한 언어로 대부분의 프로그램에서 발생하는 오류에 대해서 문법적으로 예외 처리를 해줘야한다.
모든 예외 클래스의 최상위 class는 Exception class이며 다음과 같이 Exception class에는 수많은 예외상황을 처리하기 위한 class들이 존재한다.
대표적인 예외
try {
예외가 발생할 수 있는 코드를 입력
}catch(처리할 예외 타입 e) {
try블록 안에서 예외가 발생했을 때 예외를 처리하는 부분
}
public class ArrayIndexExceptionTest {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
try { // Error가 발생할 수 있는 코드를 입력
for(int i=0; i<=5; i++) {
System.out.println(arr[i]);
}
}catch (ArrayIndexOutOfBoundsException e) {
// ArrayIndexOutOfBoundsException :배열의 크기를 넘어선 위치를 참조하려는 경우 발생
// 해당 exception이 발생하면 e라는 변수로 넘어온다~
System.out.println(e.toString());
// Result: java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
}
}
}
finally블럭은 파일이나 네트워크를 닫는 등의 리소스 해제를 구현하는 곳이다.
finally는 try블록이 수행되는 경우 무조건 수행되게 되며 catch문에서 return이 되더라도 finally문은 수행된다.
여러개의 예외 블럭이 있는 경우 각각의 블럭에서 리소스를 해제하지 않고 finally블록에서 해제하도록 구현한다.
try {
예외가 발생할 수 있는 코드를 입력
}catch(처리할 예외 타입 e) {
try블록 안에서 예외가 발생했을 때 예외를 처리하는 부분
}finally {
리소스를 해제하는 코드를 구현
}
Finally를 사용하지 않는 경우 아래의 코드와 같이 블럭별로 try-catch를 해야한다.
try {
fis = new FileInputStream("a.txt");
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
fis.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
위의 코드를 finally문을 사용하면 catch문들 아래에서 file의 close에 대한 예외상황을 더 간결하게 처리할 수 있다.
try {
fis = new FileInputStream("a.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally { // try구문이 불리면 finally는 무조건 불린다.
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("finally");
}
try{}내부에서 리소스를 사용하는 경우 close()를 하지 않아도 try{}블록에서 열린 리소스는 정상적인 경우와 예외가 발생한 경우 모두 자동으로 파일이나 네트워크가 해제된다.
java7부터 제공된 구문이다.
try (FileInputStream fis = new FileInputStream("a.txt")){
// try내부 괄호내에서 위와 같이 파일 선언을 하면 자동으로 close가 된다.
System.out.println("read");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileInputStream과 같이 해당되는 리소스 클래스가 AutoClosable 인터페이스가 구현되어 있어야 사용 가능하다. 그렇지 않은 경우 직접 인터페이스를 구현해야 한다.
java9부터는 리소스를 외부에서 선언하고 try(obj)와 같이 괄호 안에 변수만 써서 사용할 수 있다.
AutoCloseableObj.java
public class AutoCloseableObj implements AutoCloseable {
// AutoCloasble을 implement하면 close를 overriding해야한다.
@Override
public void close() throws Exception {
// TODO Auto-generated method stub
System.out.println("closing...");
}
}
AutoCloseableObjTest.java
public class AutoCloseTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
AutoCloseableObj obj = new AutoCloseableObj();
try(obj) {
throw new Exception();
}catch(Exception e) {
System.out.println("Exception");
}
System.out.println("end");
}
}
위의 코드를 실행할 경우
closing...
Exception
end
다음과 같은 결과가 나온다. 결과에서 end가 나온 것을 통해 Finally없이 ojb가 auto close가 되었다는 것을 알 수 있다.
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowException {
// Class 클래스를 사용
public Class loadClass(String fileName, String className) throws ClassNotFoundException, FileNotFoundException {
FileInputStream fis = new FileInputStream(fileName);
// throws를 통해 코드를 실제로 사용하는 곳에서 예외 처리를 하도록 미루었다.
Class c = Class.forName(className);
return c;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ThrowException test = new ThrowException();
try {
test.loadClass("a.txt", "abc");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println(e);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
System.out.println(e);
}
System.out.println("end");
}
}