✔ 자바 예외처리의 기본
예외란?
- 오류는 단순한 문법적 실수를 뜻하므로 대부분의 오류는 컴파일 과정에서 그 잘못이 드러나게 됨
- 그러나 예외는 프로그램 실행 중에 발생하는 정상적이지 않은 상황을 뜻함
- 이때 가상머신은 예외가 발생하면 그 내용을 간단히 출력하고 프로그램을 종료하게 됨
- 이 외에도 예외의 원인도 설명하지 않으며 예외에 대한 처리를 제대로 해주지 않을 경우가 존재함
- 그러므로 자바에서 예외처리는 필수
- 그러므로 예외의 처리를 가상머신이 아닌 프로그래머가 원하는 예외의 처리 방식으로 해주면 됨
예외 처리를 위한 try ~ catch
- 자바는 예외 상황별로 상황을 알리기 위한 예외 클래스를 정의하고 있음
- 관련 오류가 발생하면 가상머신은 예외 클래스의 인스턴스를 생성하고
이 인스턴스를 프로그래머가 처리하면 예외는 처리된 것으로 간주하여 프로그램을 종료하지 않음 - 그러나 이 인스턴스를 처리하지 않으면 프로그램은 그냥 종료됨
- 관련 오류가 발생하면 가상머신은 예외 클래스의 인스턴스를 생성하고
- 예외를 처리할 때는 try ~ catch문을 사용
- try 영역에서 발생한 예외 상황을 catch 영역에서 처리함
- try 영역의 실행 중간에 예외 상황이 만들어지고 이로 인해 가상 머신이 예외 클래스의 인스턴스를 생성하면,
이 인스턴스는 메소드를 호출하듯이 catch 구문의 매개변수 name에 전달되게 됨
그러면 가상머신은 catch 구문 안에서 무엇을 하든 상관없이 예외가 처리된 것으로 간주하고
try ~ catch문의 다음 문장을 이어서 실행해 나가게 됨
try {
...관찰 영역...
}
catch(Exception name) {
...처리 영역...
}
둘 이상의 예외를 처리하기 위한 구성
- 여러 예외 처리를 하고자 한다면 catch 구문을 이어서 구성하면 됨
- catch 구문은 얼마든지 이어서 구성할 수 있음
- catch 구문 안에서 둘 이상의 예외를 처리하는 것도 가능함
- 상황 별 예외의 처리 방식이 다르지 않을 경우 하나의 catch 구문 안에서 모든 예외가 처리될 수 있도록 묶는 것도 가능함
try {
...관찰 영역...
}
catch(Exception name1) {
...처리 영역...
}
catch(Exception name2) {
...처리 영역...
}
catch(Exception name3 | Exception name4) {
...처리 영역...
}
Throwable 클래스와 예외처리의 책임 전가
- 자바의 최상위 클래스인 java.lang.Object를 제외하고 예외 클래스의 최상위 클래스는 java.lang.Throwable
- 이 클래스는 발생한 예외의 정보를 알 수 있는 메소드가 정의되어 있음
- getMessage() 메소드는 예외의 원인을 담고 있는 문자열을 반환함
- printStackTrace() 메소드는 예외가 발생한 위치와 호출된 메소드의 정보를 출력함
- 메소드 호출 흐름에 따라 가상머신은 예외처리를 넘기게 되고, main에서 마저도 예외가 처리되지 않으면
가상머신이 대신 예외를 처리하게 되어 예외 관련 메시지를 출력하고 프로그램을 종료하게 됨
// 메소드 호출 흐름
main -> md1 -> md2
// 예외처리 책임 전가
md2 예외 발생 -> m2 예외처리 X -> m1 예외 처리 X -> main 예외 처리 X -> 가상머신이 예외처리
예외 상황을 알리기 위해 정의된 클래스의 종류
- 자바에서 발생시키는 예외의 종류는 다양하므로 그 수만큼 예외 클래스도 다양하게 정의되어 있음
- 대표적인 예외 클래스와 발생하는 상황
- ArrayIndexOutOfBoundsException : 배열 접근에 잘못된 인덱스 값을 사용해서 발생
- ClassCastException : 허용할 수 없는 형 변환을 진행하는 경우에 발생
- NullPointerException : null이 저장된 참조변수를 대상으로 메소드를 호출할 때 발생
✔ 예외처리에 대한 나머지 설명들
예외 클래스의 구분
- 예외 클래스의 최상위 클래스는 Throwable이며 이를 상속하는 예외 클래스는 세 부류로 나누어짐
- Error 클래스를 상속하는 예외 클래스
- Exception 클래스를 상속하는 예외 클래스
- RuntimeException 클래스를 상속하는 예외 클래스 (RuntimeException은 Exception 클래스를 상속)
- Error 클래스를 상속하는 예외 클래스는 처리할 수 있는 오류가 아니며
이런 유형의 예외가 발생하면 그냥 프로그램이 종료되도록 놔두고 이후에 원인을 파악하는 과정이 이어져야 함
- VirtualMachineError : 가상머신에 심각한 오류가 발생
- IOError : 입출력과 관련해서 코드 수준 복구가 불가능한 오류가 발생
- RuntimeException 클래스를 상속하는 예외 클래스는 대부분 코드를 수정해야 할 상황이지 예외처리를 할 상황이 아님
- ArithmeticException : 어떤 수를 0으로 나누게 되면 발생
- ArrayIndexOutOfBoundsException : 배열 접근에 잘못된 인덱스 값을 사용해서 발생
- ClassCastException : 허용할 수 없는 형 변환을 진행하는 경우에 발생
- NullPointerException : null이 저장된 참조변수를 대상으로 메소드를 호출할 때 발생
- NegativeArraySizeException : 배열 생성시 길이를 음수로 지정하는 예외의 발생
- ArrayStoreException : 배열에 적절치 않은 인스턴스를 저장하는 예외의 발생
- RuntimeException 클래스를 직접 혹은 간접적으로 상속하지 않고
Exception 클래스만 상속하는 예외 클래스는 가장 많으며 이들은 특정 클래스 또는 메소드에 연관되어 있음
Exception을 상속하는 예외 클래스의 예외처리
- Error 클래스를 상속하는 예외나 RuntimeException 클래스를 상속하는 예외의 경우 예외의 처리는 선택임
- 그러나 Exception 클래스를 상속하는 예외는 try ~ catch문으로 처리하거나
throws 선언을 추가하여 다른 영역인 이 메소드를 호출한 메소드에게 넘긴다고 반드시 명시해야 함- throws 선언을 통해서, 둘 이상의 예외에 대해 그 처리를 넘긴다는 표시를 할 수 있음
try {
...
}
catch(IOExcpetion e) {
e.printStackTrace();
}
또는
public static void md2() throws IOException {
...
}
프로그래머가 정의하는 예외
- 프로그래머가 직접 예외 클래스를 정의하고 이를 기반으로 특정 상황에서 예외가 발생하도록 할 수 있음
- 프로그래머가 직접 예외 클래스를 정의할 때는 Exception을 상속한 후
생성자에 상위 클래스의 생성자를 호출하면서 예외 상황에 대한 설명을 담고 있는 문자열을 전달함 - 전달된 문자열은 Throwable 클래스에 정의된 getMessage() 메소드를 호출할 시 반환되게 됨
- 프로그래머가 직접 예외 클래스를 정의할 때는 Exception을 상속한 후
class ReadAgeException extends Exception {
public ReadAgeException() {
super("유효하지 않은 나이가 입력되었습니다.");
}
}
try {
....
}
catch(ReadAgeException e) {
System.out.println(e.getMessage());
}
if(age < 0)
throw new ReadAgeException();
finally 구문
- finally 구문은 코드의 실행이 try 안으로 진입하면 무조건 실행되게 됨
- try에서 예외가 발생하건 안 하건, catch가 실행되건 안되건, 무조건 실행됨
- try에 이어서 finally 구문을 두거나, try ~ catch ~ finally를 하나의 문장으로 묶을 수도 있음
- 또한 finally 내에서도 try ~ catch문을 작성할 수 있음
BufferedWriter writer = null;
try {
writer = Files.newBuffredWriter(file);
writer.write('A');
writer.write('Z');
}
catch(IOException e) {
e.printStackTrace();
}
finally {
try {
if(writer != null)
writer.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
try-with-resources 구문
- try에 이어 등장하는 소괄호 안에서는 종료의 과정을 필요로 하는 리소스를 생성할 수 있음
- 그러면 java.lang.AutoCloseable 인터페이스의 close 메소드를 호출하게 됨
- 그러므로 이 리소스는 try-with-resources문을 빠져나오면서 자동으로 종료되게 됨
- 둘 이상의 리소스에 대해서도 ;로 구분하여 구성할 수 있음
- 앞선 finally 구문을 간결하게 표현할 수 있으므로 사용 가능한 상황에서는 적극 사용 권장
try(resource) {
...
}
catch(Exception name) {
...
}
BufferedWriter writer = null;
try(BufferedWriter writer = Files.newBuffredWriter(file)) { // writer.close(); 문장을 넣지 않아도 호출됨
writer.write('A');
writer.write('Z');
}
catch(IOException e) {
e.printStackTrace();
}
'Java-Spring > 열혈 Java 프로그래밍' 카테고리의 다른 글
[Java] 자바의 기본 클래스 (0) | 2023.08.10 |
---|---|
[Java] Object 클래스 (0) | 2023.08.08 |
[Java] 인터페이스와 추상 클래스 (0) | 2023.08.07 |
[Java] 클래스의 상속 (0) | 2023.08.05 |
[Java] 배열 (0) | 2023.08.04 |