오류와 예외의 차이
- 오류는 일반적으로 회복이 불가능한 문제
- 시스템 레벨에서, 주로 환경적인 이유로 발생
- 예외는 일반적으로 회복이 가능한 문제
- 그 예외가 발생할 수 있다는 것을 인지하고, 대응했을 것. 아니라면 해야한다. 이를 대응하는 것이 예외처리
예외의 종류
코드 실행 관점에서 예외의 종류
- 컴파일 에러 (예외)
- 대부분 자바 프로그래밍 언어의 규칙을 지키지 않아서 발생
- 그냥 다시 문법에 맞게 작성하면 됨
- 런타임 에러 (예외)
- 주로 다루게 될 에러 (예외)
- 문법적인 오류는 아니라서 컴파일은 잘 되었지만, 프로그램이 실행 도중 마딱드리게 되는 예외
예외처리 관점에서 예외의 종류
- 확인된 예외 ( Checked Exception )
- 컴파일 시점에 확인하는 예외
- 반드시 예외 처리를 해줘야함
- 미확인된 예외 ( Unchecked Exception )
- 런타임 시점에 확인되는 예외
- 예외처리가 필수는 아님
예외 발생과 try-catch, finally 문
class OurBadException extends Exception {
public OurBadException() {
super("위험한 행동을 하면 예외처리를 꼭 해야합니다!");
}
}
우선 Exception 클래스를 부모클래스로 둔 OurBadException 클래스를 생성해서 위와 같이 예외를 정의했다.
class OurClass {
private final Boolean just = true;
// 신규 문법 throws!
public void thisMethodIsDangerous() throws OurBadException {
if (just) {
// 신규 문법 throw!
throw new OurBadException();
}
}
}
just 이름으로 Boolean 변수를 선언했고 final 로 수정을 막았기 때문에 항상 true 로 무조건 예외를 처리할 수 있도록 했다.
우리가 thisMethodisDangerous 메서드를 선언하면서 이 메서드는 예외가 발생할 수 있는 위험한 코드라고 미리 인지 ( 예측 ) 했다. 그래서 우리는 이에 Flag 를 달아 확인하고자 해서 throws 문법을 OurbadException 클래스로 달아줬다.
그리고 실제로 문제가 있다면 throw new OurBadException(); 을 통해서 이 메서드가 위험하다고 알렸다.
public class StudyException {
public static void main(String[] args) {
OurClass ourClass = new OurClass();
try {
// 1. 위험한 메소드의 실행을 "시도" 해 봅니다.
// "시도" 해보는 코드가 들어가는 블럭입니다.
ourClass.thisMethodIsDangerous();
} catch (OurBadException e) {
// 2. 예외가 발생하면, "잡아서" handling 합니다.
// 예외가 발생하는경우 "handling" 하는 코드가 들어가는 블럭입니다.
// 즉 try 블럭 내의 구문을 실행하다가 예외가 발생하면
// 예외가 발생한 줄에서 바로 코드 실행을 멈추고
// 여기 있는 catch 블럭 내의 코드가 실행됩니다.
System.out.println(e.getMessage());
} finally {
// 3. 예외의 발생 여부와 상관없이, 실행시켜야 하는 코드가 들어갑니다.
// 무조건 실행되는 코드가 들어가는 블럭입니다.
System.out.println("우리는 방금 예외를 handling 했습니다!");
}
}
}
우선 try 를 시도해본다. 만약 여기서 예외가 발생했다? 그럼 catch 로 잡아서 그 안에 코드를 실행시킨다.
이후 catch 진입 여부와는 상관없이 finally 내부 코드를 실행시킨다.
이를 예외를 handling 한다고 한다.
- 여기서 catch () 괄호 안에는 어떤 예외 클래스를 받아서 처리할지 정의해주어야한다.
- 모든 예외를 다 받고 싶으면 Exception 을 넣어주고 일부 예외만 받아서 처리하고 싶으면 위와 같이 해당 예외 클래스명을 넣어주면 된다.
- 1개의 try 문에 여러 개의 catch 문을 사용해도 된다.
- 위 예시는 Checked Exception 을 다룸
- 메서드를 선언할 때 예외가 발생하는 위험한 메서드라는 것에 throws/throw 를 달아 알렸다.
- 우리가 checked exception 을 정의하고 알렸으니 이 메서드를 사용할 때 예외처리를 하지 않으면 컴파일 에러가 발생한다.
예외 클래스 구조
시작은 모든 객체의 원형인 Object 클래스에서 시작
"문제 상황" 을 뜻하는 Throwable 클래스가 Object 클래스를 상속
RuntimeException 을 상속한 예외들은 UncheckedException, 반대로 상속하지 않은 예외들은 CheckedException 으로 구현
Chained Exception
- 예외는 다른 예외를 유발시킬 수 있다.
- 예외 A 가 예외 B 를 발생시켰다면 예외 A는 B의 원인 예외.
- 이 원인 예외를 새로운 예외에 등록한 후 다시 새로운 예외를 발생시키는데, 이를 예외 연결 이라고 한다.
initCause() : 지정한 예외를 원인 예외로 등록하는 메서드
getCause() : 원인 예외를 반환하는 메서드
실제 예외 처리
1. 예외 복구하기
public String getDataFromAnotherServer(String dataPath) {
try {
return anotherServerClient.getData(dataPath).toString();
} catch (GetDataException e) {
return defaultData;
}
}
- try-catch 로 예외 처리하고 정상상태로 복구하는 방법
- 가장 기본적인 방식이지만, 현실적으로 복구가 가능한 상황이 아닌 경우가 많거나 최소한의 대응만 가능한 경우가 많기 때문에 자주 사용되지는 않음
2. 예외 처리 회피하기
public void someMethod() throws Exception { ... }
public void someIrresponsibleMethod() throws Exception {
this.someMethod();
}
- 이렇게 처리하면, someMethod()에서 발생한 에러가 someIrresponsibleMethod()의 throws를 통해서 그대로 다시 흘러나감 (물론 같은 객체 내에서 이런 일은 하지 않음.)
- 관심사를 분리해서 한 레이어에서 처리하기 위해서 이렇게 에러를 회피해서 그대로 흘러 보내는 경우도 있음
3. 예외 전환하기
- 해당 예외보다 좀 더 적절한 예외를 던져줌
- RuntimeException 처럼 일괄적으로 처리하기 편한 예외로 바꿔서 던지고 싶은 경우에도 사용
'컴퓨터 프로그래밍 > Java' 카테고리의 다른 글
[Java] Collection 과 Wrapper 객체 (0) | 2024.08.05 |
---|---|
[Java] Generic (0) | 2024.08.04 |
[Java] 인터페이스 (0) | 2024.07.30 |
[Java] 상속 (0) | 2024.07.29 |
[Java] this와 this(), 접근 제어자, package와 import (0) | 2024.07.29 |