1. 예외 클래스
1. 오류란 무엇인가요?
프로그램 오류의 발생 시점에 따라 2가지로 구분할 수 있다.
<프로그램 오류>
1) 컴파일 오류(compile error)
컴파일 오류는 코드 작성 중 실수로 발생하는 문법적인 오류다.
2) 실행 오류(runtime error)
실행 오류는 컴파일 오류는 없으나 프로그램 실행 중 발생하는 오류다.
- 버그는 실행 오류 중 프로그램을 잘못 구현하여 의도와 다르게 실행되어 생기는 오류다.
런타임 오류로 인한 프로그램이 비정상 종료되는 것을 방지하기 위해 예외 처리를 한다. 예외가 발생했을 때 로그를 남겨두면 예외 상황을 파악하고 버그를 수정하는데 도움을 받을 수 있다.
2. 오류와 예외
<실행 오류(런타임 에러)>
1) 시스템 오류(error)
Error 는 JVM에서 발생하는 오류로 프로그램 코드로 제어할 수 없는 심각한 오류다.
- 스택 오버플로우, 메모리 부족 등
2) 예외(exception)
Exception 은 프로그램 코드로 제어할 수 있는 error 보다 낮은 단계의 오류다.
- 프로그램에서 읽어야 할 파일이 없는 경우, 베열 값을 출력하는데 배열 요소가 없는 경우 등
오류 클래스는 모두 Throwable 클래스에서 상속을 받느다.
Error 클래스의 하위 클래스는 시스템 오류를 다루며
Exception 클래스의 하위 클래스는 예외를 다룬다.
3. 예외 클래스의 종류
1) IOException: 입출력에 대한 예외
2) RuntimeException: 프로그램 실행 중 발생할 수 있는 오류에 대한 예외
(주의) uncked 예외(try-catch 문으로 예외 처리를 하지 않아도 컴파일 오류X)로 프로그래머가 알아서 처리해야함
3) FileNotFoudException: 디스크에 없는 파일에 대한 액세스 시도에 대한 예외
4) ArithmeticException: 산술 연산 중 발생할 수 있는 예외(0으로 숫자 나누는 경우 등)
5) IndexOutOfBoundException: 잘못된 인덱스를 사용해 배열에 접근했을 때 예외
2. 예외 처리하기
1. try-catch 문
catch () 안의 예외 타입은 예외 상황에 따라 달라진다.
1) try-catch 문 사용하기
ArrayIndexOutOfBounds는 배열의 인덱스 범위를 벗어날 때 예외가 발생한다. 이 클래스는 RuntimeException의 하위 클래스이므로 unchecked 예외이기 때문에 프로그램이 비정상 종료되지 않도록 예외처리를 해주어야 한다.
2. 컴파일러에 의해 예외가 체크되는 경우(cheked 예외)
RuntimeException과 달리 컴파일러가 예외 처리를 확인하는 checked 예외는 프로그래머가 예외 처리를 하지 않으면 컴파일 오류가 난다.
1) 파일 입출력에서 발생하는 예외 처리하기
파일 입출력에서 발생하는 FileNotFoundException은 checked 예외로 예외 처리를 하지 않으면 컴파일 오류가 발생한다. 예외 처리를 하면 예외 상황을 알려주는 메시지를 볼 수 있고 프로그램이 비정상 종료되지 않고 계속 수행되도록 할 수 있다.
try{
FileInputStream fis = new FileInputStream("a.txt");
}catch(FileNotFoundException e){
e.printStackTrace(); // 어디에서 예외가 발생했는지 추적
System.out.println(e); // 예외 클래스의 toString() 호출
}
만약 열려고 하는 파일(a.txt)이 없다면 catch 문을 수행한다.
3. try-catch-fianlly 문
어떠한 경우에도 항상 수행되어야 하는 코드는 finally 블록에 작성한다. try 나 catch 문에 return 문이 있어도 finally 문은 항상 수행된다!
시스템에서 허용하는 자원은 한계가 있으므로 사용한 시스템 리소스는 사용 후 반드시 close() 메서드로 닫아주어야 한다. 즉, 프로그램이 정상 종료되든 비정상 종료되든 리소스는 닫아야 한다.
try{
FileInputStream fis = new FileInputStream("a.txt");
}catch(FileNotFoundException e){
System.out.println(e); // 예외 클래스의 toString() 호출
return; // return 문이 있어도 finally 문은 항상 수행
} finally {
if(fis != null) {
try {
fis.close(); // 파일 입력 스트림 닫기
} catch(IOException e) {
e.printTrace();
}
}
}
try-catch-catch.. 각 블록마다 리소스를 해제할 필요 없이 finally 블록에서 리소스를 한번만 해제하면 된다.
단, 리소스를 해제하는 close() 문장도 예외처리를 해주어야 한다.
4. try-with-resources 문
자바7부터는 try-with-resources 문을 제공하여 close() 메서드를 명시적으로 호출하지 않아도 try 블록 내에서 열린 리소스를 자동으로 닫도록 할 수 있다.
try-with-resources를 사용하려면 해당 리소스가 AutoCloseable 인터페이스를 구현해야 한다.
FileInputStream 클래스는 AutoCloseable 인터페이스를 구현하고 있어 close()를 명시적으로 호출하지 않아도 자동으로 close() 메서드가 호출된다.
1) AutoCloseable 인터페이스
AutoCloseable 인터페이스에는 close() 메서드가 있다. AutoCloseable 인터페이스를 구현한 클래스는 close()를 명시적으로 호출하지 않아도 자동으로 close() 메서드가 호출된다.
리소스를 여러개 생성할 때는 세미콜론(;) 으로 구분하여 선언한다.
// 1. 정상 종료되는 경우
try(FileInputStream fis = new FileInputStream("a.txt")){
}catch(FileNotFoundException e){
System.out.println(e); // 예외 클래스의 toString() 호출
}
// 2. 예외 발생으로 종료되는 경우
try(FileInputStream fis = new FileInputStream("a.txt")){
throw new Exception(); // 강제 예외 발생
}catch(FileNotFoundException e){
System.out.println(e); // 예외 클래스의 toString() 호출
}
정상 종료되든 예외가 발생하여 종료되든 자동으로 리소스의 close() 메서드가 호출되어 리소스가 해제된다. 예외 발생으로 종료되는 경우, 리소스의 close() 호출 → catch 문 순으로 수행된다.
2) 향상된 try-with-resources문(자바 9부터 추가)
자바7에서는 AutoCloseable 인터페이스를 구현한 리소스의 변수 선언을 try 문 괄호 안에서 해야했다.
하지만 자바9부터는 try문의 괄호 안에서 외부에서 선언한 리소스 변수를 쓸 수 있다.
// 자바7
AutoCloseObj obj = new AutoCloseObj();
// 다른 참조 변수로 다시 선언
try(AutoCloseObj obj2 = obj) {
} catch(Exception e) {
}
// 자바9
AutoCloseObj obj = new AutoCloseObj();
// 외부에서 선언한 변수 바로 사용
try(obj) {
} catch(Exception e) {
}
3. 예외 처리 미루기
1. 예외 처리를 미루는 throws 사용하기
thorws 예약어를 사용한 예외 던지기는 예외를 해당 메서드에서 처리하지 않고 메서드를 호출하여 사용하는 부분에서 예외 처리를 하는 방법이다. 어떤 메서드가 다른 여러 코드에서 호출되어 사용된다면 호출하는 코드의 상황에 맞게 로그를 남기거나 예외 처리를 하는 것이 좋다. 따라서 이러한 경우, throws를 사용하여 메서드 호출부분에서 예외 처리를 하도록 하는 것이 좋다.
<throws를 활용하여 예외 처리 미루기>
throws를 메서드의 선언부에 추가하면, 그 메서드를 호출하여 사용하는 부분에서 예외 처리를 해야한다.
1) 하나의 catch 문에서 여러 예외를 한 문장으로 처리
catch 문 괄호 안에 예외 클래스를 모두 적고 한 문장으로 예외 처리를 하는 방식이다.
try{
} catch(FileNotFoundException | ClassNotFoundException e) {
e.printStackTrace(); // 모든 예외를 동일하게 처리
}
2) 각 상황마다 catch 문으로 예외 처리
throws에서 넘긴 예외 클래스 수 만큼 catch 문이 생성된다.
각 예외 상황마다 다른 방식으로 처리해야 하고 로그도 다르게 남겨야하는 경우 사용하는 방식이다.
try{
} catch(FileNotFoundException e){
e.printStackTrace();
} catch(ClassNotFoundException e) {
e.getMessage();
}
2. 다중 예외 처리
unchecked 예외를 처리해야하는 경우 즉, 어떤 예외가 발생할지 미리 알 수 없지만 모든 예외 상황을 처리해야할 때 맨 마지막 catch 문에서 Exception 클래스를 활용한다.
(주의) Exception 클래스는 모든 예외 클래스의 최상위 클래스로 맨 위에 catch(Exception e) 문장을 쓰면 발생하는 모든 예외 클래스가 Exception 상위 클래스로 자동 형 변환되어 오류가 발생한다.
그러므로 기본 예외 처리를 하는 Exception 클래스 catch문은 여러 예외 처리 블록의 가장 아래에 위치해야 한다.
4. 사용자 정의 예외
자바에서 제공하는 예외 처리 클래스 외에 개발하는 프로그램에 따라 다양한 예외 상황이 발생할 수 있다.
1. 사용자 정의 예외 클래스 구현하기
사용자 정의 예외 클래스를 구현할 때는 기존 JDK에서 제공하는 예외클래스 중 가장 유사한 예외 클래스를 상속 받는 것이 좋다. 잘 모를 땐 최상위 Exception 클래스를 상속받으면 된다.
2. 예외 처리를 할 때는 로그를 잘 남기자
[참고] https://sgcomputer.tistory.com/83
[참고] https://kephilab.tistory.com/83
'Java > Do It! 자바 프로그래밍' 카테고리의 다른 글
[JAVA] 15-2. 자바 입출력_표준 입출력 (0) | 2022.05.11 |
---|---|
[JAVA] 15-1. 자바 입출력_자바 입출력과 스트림 (0) | 2022.05.11 |
[JAVA] 13-3. 스트림 (0) | 2022.05.10 |
[JAVA] 13-2. 람다식 (0) | 2022.05.10 |
[JAVA] 13-1. 내부 클래스 (0) | 2022.05.10 |