먼저 해당 글은 Java의 오류처리를 기반으로 설명한다!
자바 프로그래밍 중 발생하는 오류를 크게 2가지 범주로 나누면, 아래 2가지로 나눌 수 있다.
예외처리는 개발자 입장에서 보면, 참으로 귀찮은 작업인듯하다...
하지만 예외처리 만큼 중요한 작업도 없다!!
예외처리를 통해 개발자는 프로그램이 비정상 종료를 피하도록 하여 시스템이 원할이 실행되도록 하기 때문이다.
그렇다면 모든 에러를 어떻게 예측할것인가??....
개발자가 compile time에서가 아닌 runtime 시 발생한 오류의 경우 오류의 과정을 재현하는 것은 현실적으로 힘들다
따라서 개발자들은 생각했다 기록(log)을 남기자!
log 분석을 통해 그 원인을 파악하여 bug를 수정하는 것이다.
자바는 안전성이 중요한 언어로 대부분 프로그램에서 발생하는 오류에 대해 문법적으로 예외 처리를 해야한다!
그림에서 나타내듯, 모든 예외 클래스의 최상위 클래스는 Exception 클래스이다.
자바에서는 다양한 예외들에 대해 그 처리를 위한 클래스가 제공되고 있기 때문에 이는 다 정리할 수 없을 듯 하다. 필요하면 그때 그때 찾아보면서 해결하는 걸로!!
만약 내가 발생시키고 싶은 에러가 없다면...? 예외처리를 상속받은 CustomClass를 생성하자 !
일반적으로 우리가 알 고 있는 try catch 문법이다.
public class FileExceptionHandling {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("a.txt");
} catch (FileNotFoundException e) {
System.out.println(e);
return;
}finally{
if(fis != null){
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("항상 수행.");
}
}
}
위의 코드를 예시로 든다면, 파일 작업이 필요할 때, 개발자는 파일을 열고 작업을 한다.
그런데 예외가 발생한다고 해서 열어둔 파일을 닫지 않는 것은 메모리 낭비이다!
따라서 이와 같은 경우 처럼 항상 수행 되어야 하는 경우
finally {} 내부에 정의하면, 위와 같이 catch {} 내부에 return 이 있다고 한들 항상 finally는 실행이 된다
이 문법은 자바 7부터 제공되고 있는 문법이다.
위와 같이 리소스에 대한 접근이 있고 항상 close가 필요한 경우에 사용할 수 있다!
리소스를 try() 내부에서 선언해야만 하며, close()를 명시적으로 호출하지 않아도 try{}블록에서 열린 리소스는 정상적인 경우나 예외가 발생한 경우 모두 자동으로 해제된다.
해당 리소스 클래스가 AutoCloseable 인터페이스를 구현 해야 함
FileInputStream의 경우에는 AutoCloseable을 구현하고 있다고 한다!
자바 9 부터 리소스는 try() 외부에서 선언하고 변수만을 try(obj) 와 같이 사용할 수 있음
public class AutoCloseObj implements AutoCloseable{
@Override // 구현체
public void close() throws Exception {
System.out.println("리소스가 close() 되었습니다");
}
}
public class AutoCloseTest {
public static void main(String[] args) {
AutoCloseObj obj = new AutoCloseObj();
try (obj){
throw new Exception();
}catch(Exception e) {
System.out.println("예외 부분 입니다");
}
}
}
예외 처리는 위와 같이 예외가 발생하는 문장에서 try-catch 블록으로 처리하는 방법과 이를 사용하는 부분에서 처리하는 방법 두 가지가 있다!
throws를 이용하면 예외가 발생할 수 있는 부분을 사용하는 문장에서 예외를 처리할 수 있다
이 또한 코드를 통해 이해하자
class ThrowsException {
// 클래스 객체 반환 함수
public Class loadClass(String fileName, String className) throws FileNotFoundException, ClassNotFoundException{
FileInputStream fis = new FileInputStream(fileName); //FileNotFoundException 발생
Class c = Class.forName(className); //ClassNotFoundException 발생
return c;
}
public static void main(String[] args) {
ThrowsException test = new ThrowsException();
try {
test.loadClass("a.txt", "java.lang.String");
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
위 와 같은 구조로 오류가 발생할 수 있는 메서드 내부에서 발생하는 오류를 메서드 내에서 처리하지 않고 메인 메서드로 예외처리를 위임하는 것이 throw 이다!
앞에서도 로그의 중요성에 대해 언급했던 것 같은데.. 다시 한번 짚고 넘어가겠다
로그(log)란? 시스템 운영에 대한 기록이다 (error 상황만 기록하는 것은 아님)
정해진 것은 없다. 다만
너무 적은 로그는 어떠한 에러의 발생 이후, 정확한 시스템의 상황을 파악하기 어렵다
반면,
너무 많은 로그는 빈번한 file I/O가 발생으로 인한 오버헤드와 로그 파일의 백업 문제등 다양한 추가작업이 존재한다는 수고스럼움이 있다.
음... 적당량의 로그를 남기며 부족하면 늘리고 많다면 줄이면서 합의점을 찾아야 하는 듯 하다.
자바에서 기본적으로 제공되는 log package이며, 파일이나 콘솔에 로그 내용을 출력할 수 있다!
jre/lib/logging.properties 파일을 편집하여 로그의 출력방식 로그 레벨을 변경 할 수 있다고 한다.
logging 패키지에서 제공하는 로그 레벨은 severe, warning, info, config, fine, finer, finest 이며 상황에 맞게 적절한 로그 레벨을 부여하자!
나 같은 경우에는 Springboot 개발에서는 오픈소스로는 log4j 를 많이 사용하고 있다!!
성가시고 귀찮기만한 Error Handling 하지만 이보다 중요한 것은 없다!!
오늘은 자바에서의 예외처리에 대해 정리하고 알아보는 시간을 가졌다.
다음번에는 Log4j 와 같은 흔히 사용하는 로깅 오픈소스에 대해서 한번 까봐야 겠다 ㅎㅎ
fastcampus : 한번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online. ch6/9-11