예외처리
2025. 2. 25. 15:23ㆍJava/Java 문법
1. 프로그램 오류
- 프로그램이 오작동하거나 비정상적으로 종료되게 하는 원인들
- 프로그래밍에서는 오류를 발생 시점에 따라 크게 3가지로 나눈다.
- 컴파일 에러(compile-time error) : 컴파일시에 발생하는 에러
- 런타임 에러(runtime error) : 실행시에 발생하는 에러
- 논리적 에러(logical error) : 실행은 되지만 의도와 다르게 동작하는것
- 자바 프로그래밍에서는 실행 시(runtime) 발생할 수 있는 오류를 '에러(error)'와 '예외(exception)' 두가지로 구분 하였다.
2. 에러(Error)와 예외(Exception)
2-1. 에러(error)
- 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
- 시스템 상에서 프로그램에 심각한 문제가 발생하여 실행중인 프로그램이 종료되는 것
- 개발자가 미리 예측하거나 코드로 처리하는 것이 불가능한 경우
- ex: JVM 에러(메모리 부족(OutOfMemoryError), 스택오버플로우(StackOverflowError) 등..), 정전, 컴퓨터 자체 하드웨어적인 문제 등
2-2. 예외(exception)
- 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류
- 발생할 수 있는 상황을 개발자가 미리 예측하고 처리할 수 있는 미약한 오류
- 예외 상황의 경우는 개발자가 적절히 처리하여 코드의 흐름을 컨트롤할 수 있다.
2-3. 예외 처리 (exception handling)
- 예외 처리: 프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 행위를 말한다.
- 예외 처리의 목적: 예외의 발생으로 인한 실행중인 프로그램의 갑작스런 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것이다.
- 또한 개발 시에도 디버깅을 용이하게 해서 예외가 발생한 원인과 위치도 쉽게 파악할 수 있어 용이하다.
- 예외처리는 자기 자신이 아니라 호출한 쪽에서 처리하도록 유도한다. (호출한 쪽에서 try~catch로 예외 처리)
3. 예외 클래스
3-1. 예외 클래스의 종류
- 오류와 예외는 모두 Throwable을 상속 받는다.
- 예외의 최상위 클래스는 Exception 클래스이다.
3-2. 예외 종류
- Unchecked Exception (언체크 예외, 런타임 예외)
- 실행 중에 발생하는 예외
- 기본적 이미 처리되어 있어 개발자가 명시적으로 예외처리 할 필요없음
- 해당 예외가 발생하지 않도록 프로그램을 잘 작성하는 것이 중요함.
- 실행 중인 프로그램이 종료되도록 작성되어 있다.
- Chekced Exception (체크 예외)
- 컴파일 단계에서 반드시 처리해야하는 예외
- 예외 처리를 하지 않으면 컴파일 에러가 발생한다.
3-3. RuntimeException
- RuntimeException타입의 예외들은 런타임 시점에 해당 예외 클래스 타입의 Exception이 발생한다.
- RuntimeExcpetion 후손 클래스 몇 가지
// 1. ArithmeticException
//0으로 나누는 경우 발생
int dividend = 3;
System.out.println(dividend / 0); //ArithmeticException
// 2. ArrayIndexOutOfBoundsException
//배열의 index범위를 넘어서 참조하는 경우 발생
int[] intArr = new int[0];
System.out.println(intArr[1]);
// 3. NullPointerException
//인스턴스가 참조되지 않은 상태(Null)로 인스턴스에 접근하는 경우 발생
int[] intArr = null;
System.out.println(intArr[0]);
// 4. ClassCastException
//형변환(Cast연산자 사용) 시 자료형에 문제가 있을 때 발생
Object obj = new String("hello");
int num = (Integer)obj;
// 5. NegativeArraySizeException
//배열 크기를 음수로 지정한 경우 발생
int[] intArr = new int[-1];
4. 예외 처리 방법
4-1. try-catch(-finally)로 처리
발생한 Exception을 직접 처리하는 방식이다.
- try 블럭: 예외(Exception)가 발생할 가능성이 있는 코드를 포함하여 작성하는 블럭
- catch블럭: try 블럭에서 예외 발생 시 해당 예외 타입(Exception 클래스 타입)에 대한 처리를 기술하는 블럭
여러 개의 catch블럭을 이어서 사용할 수 있으며 상위 타입의 예외를 처리하는 catch 블럭이 아래 쪽에 위치해야 한다. - finally 블럭: 예외 발생 여부와 상관 없이 꼭 실행되어 처리해야 할 코드가 있으면 작성하는 블럭이다.
주로 java.io나 java.sql 패키지의 메소드 처리 시 자원 반납을 위해 사용한다. - 예외가 발생한 경우 실행 순서: try -> catch -> finally
예외가 발생 하지 않은 경우 실행 순서: try -> finally
4-2. try-with-resource 구문
- 자바 7버전에서 추가된 기능으로 입출력에서 사용되는 스트림의 자원 반납 close()를 finally 블럭을 사용하지 않고 용이하게 처리하기 위해 도입된 문법이다.
- try 블록에 괄호()를 추가하여 파일을 열거나 자원을 할당하는 명령문을 명시하면, 해당 try 블록이 끝나자마자 자동으로 파일을 닫거나 할당된 자원을 해제해 준다.
//finally 사용하여 자원 해제
FileWriter file = null;
try {
file = new FileWriter("data.txt");
file.write("Hello World");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
file.close(); //// close()에서 발생하는 예외처리도 필수
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//finally를 쓰지 않고 try옆 ()에 자원 할당 -> try 블록 끝나면 자동으로 close()
try (FileWriter file = new FileWriter("data.txt")) { // 파일을 열고 모두 사용되면 자동으로 닫아준다
file.write("Hello World");
} catch (IOException e) {
e.printStackTrace();
}
4-3. throws로 위임
- 메서드가 예외를 직접 처리하지 않고 호출한 쪽으로 던짐
- Exception이 발생하는 메소드(또는 생성자)를 호출한 상위 메소드에게 처리를 위임하는 방식이다.
- 메서드에 예외를 선언하려면 메서드의 선언부에 throws를 사용해서 메서드 내에서 발생할 수 있는 예외를 적어주면 된다. 만일 모든 예외의 최고 조상인 Exception 클래스를 메서드에 선언하면 이 메서드는 모든 종류의 예외가 발생할 가능성이 있다는 뜻이다.
4-4. throw
- throw를 사용하면 직접 예외를 발생시킬 수 있다.
- 연산자 new를 이용하여 발생시키려는 예외 클래스의 객체를 만들고 throw로 해당 객체 던지기
public void checkAge(int age) {
if (age < 18) {
throw new IllegalArgumentException("18세 이상만 가능합니다.");
}
}
5. 사용자 정의 예외
- 기존의 정의된 예외 크래스 외에 필요에 따라 프로그래머가 새로운 예외 클래스를 정의하여 사용할 수 있다.
- class MyException extends Exception { ... } -> Exception 클래스 상속받기
- 그러나 되도록 기존의 예외클래스를 활용하는 것이 좋음
class MyException extends Exception {
public MyException(String message) {
super(message);
}
}
public class Main {
public static void main(String[] args) {
try {
throw new MyException("사용자 정의 예외 발생");
} catch (MyException e) {
System.out.println(e.getMessage());
}
}
}
6. 오버라이딩 시 예외 발생 가능 범위
상속 시 오버라이딩하는 메소드는 부모 클래스의 원본 메소드보다 더 상위 타입의 예외를 발생 시키면 안된다.
public class SuperClass { //부모 클래스
public void method() throws IOException { }
}
public class SubClass extends SuperClass { //자식 클래스
//✅ 1. 예외 없이 오버라이딩 가능
//@Override
//public void method() {} //정상
//✅ 2. 같은 예외를 던져주는 구문으로 오버라이딩 가능
//@Override
//public void method() throws IOException {} //정상
// ❌ 3. 부모의 예외처리 클래스보다 상위의 예외로는 후손클래스에서 오버라이딩 불가
//@Override
//public void method() throws Exception {} //에러
//✅ 4. 하지만 부모의 예외처리 클래스보더 더 하위에 있는 예외는 오버라이딩 가능
@Override
public void method() throws FileNotFoundException {} //정상
}