1. 오류(Error) vs 예외(Exception)
1) 오류 :
- 오류는 일반적으로 회복이 불가능한 문제
- 주로 시스템 레벨, 또는 주로 환경적인 이유로 발생한다.
2) 예외 :
- 코드에 예외가 발생할 수 있다는 것을 인지하고 대응했을 때 회복이 가능한 문제
- 현실적으로 코드레벨에서 다룰 수 있는 문제상황은 '예외처리'에 속한다.
2. 코드실행 관점에서 예외의 종류
1) 컴파일 에러(예외)
- .java 파일을 .class 파일로 컴파일할 때 발생하는 에러
- 주로 문법 오류
2) 런타임 에러(예외)
- 주로 다루게될 에러(예외)
- 문법적인 오류는 아니라서 컴파일은 잘 되었지만 프로그램이 실행도중 맞닥뜨리게 되는 예외
3. 예외처리 관점에서 예외의 종류
1) 확인된 예외(Checked Exception)
- 컴파일 시점에 확인하는 예외
- 반드시 예외처리를 해줘야 함!
2) 미확인된 예외(Unchecked Exception)
- 런타임 시점에서 확인되는 예외
- 예외 처리가 반드시 필요하지는 않음
4. 예외 발생과 try-catch, finally 문
1) 예외 정의하기 : 예외 클래스를 만들어 예외를 정의할 수 있다.
class OurBadException extends Exception {
public OurBadException() {
super("위험한 행동을 하면 예외처리를 꼭 해야합니다!");
}
}
2) 우리의 메서드가 위험하다고 알리기(throw, throws)
class OurClass {
private final Boolean just = true;
// 신규 문법 throws!
public void thisMethodIsDangerous() throws OurBadException {
if (just) {
// 신규 문법 throw!
throw new OurBadException();
}
}
}
- throws : 메서드 이름 뒤에 붙어 이 메서드가 어떤 예외사항을 던질 수 있는지 알려주는 예약어, 여러 종류의 예외사항도 가능
- throw : 메서드 안에서 실제로 예외 객체를 던질 때 사용하는 예약어
3) 예외를 handling 해보기 (try-catch, finally)
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(탐지할 예외) : 예외가 발생하면 잡아서 handling 한다!
- finally : 예외의 발생 여부와 상관없이 실행시킨다.
5. 연결된 예외(Chained Exception)
- 예외는 다른 예외를 유발 할 수 있으며 만약 예외 A가 예외 B를 발생시켰다면, 예외 A는 B의 원인예외가 된다.
- 원인 예외를 새로운 예외에 등록한 후 다시 새로운 예외를 발생시키는데, 이를 예외 연결이라고 한다.
- 예외를 연결함으로써 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다룰 수 있으며 Checked Exception을 Unchecked Exception으로 포장하는데 유용하게 쓰일 수 있다.
- 원인 예외를 다루기 위한 메서드
- initCause() : 지정된 예외를 원인 예외로 등록하는 메서드
- getCause() : 원인 예외를 반환하는 메서드
// 연결된 예외
public class main {
public static void main(String[] args) {
try {
// 예외 생성
NumberFormatException ex = new NumberFormatException("가짜 예외이유");
// 원인 예외 설정(지정한 예외를 원인 예외로 등록)
ex.initCause(new NullPointerException("진짜 예외이유"));
// 예외를 직접 던집니다.
throw ex;
} catch (NumberFormatException ex) {
// 예외 로그 출력
ex.printStackTrace();
// 예외 원인 조회 후 출력
ex.getCause().printStackTrace();
}
// checked exception 을 감싸서 unchecked exception 안에 넣습니다.
throw new RuntimeException(new Exception("이것이 진짜 예외 이유 입니다."));
}
}
// 출력
Caused by: java.lang.NullPointerException: 진짜 예외이유
6. 실제 예외 처리 방법 3가지
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) 예외 전환하기
public void someMethod() throws IOException { ... }
public void someResponsibleMethod() throws MoreSpecificException {
try {
this.someMethod();
} catch (IOException e) {
throw new MoreSpecificException(e.getMessage());
}
}
- 예외처리 회피하기의 방법과 비슷하지만, 조금 더 적절한 예외를 던져주는 경우이다.
- 보통은 예외처리에 더 신경쓰고싶은 경우나, 오히려 RuntimeException처럼 일괄적으로 처리하기 편한 예외로 바꿔서 던지고 싶은 경우 사용한다.
여태 코드를 팀 프로젝트를 하거나 개인 과제를 할 때 예외처리를 제대로 하지 않은 경우가 있었다. 하지만 본인이 예상치 못한 입력이 들어올 수도 있는 등 많은 상황들이 발생할 때 프로그램의 비 정상적인 종료를 막아주고 더욱 견고하게 만들기 위해 예외처리를 조금 더 신경 써야겠다.
'개발 공부 > Java' 카테고리의 다른 글
Java 문법 정리 9. 추상클래스, 인터페이스 (0) | 2023.10.31 |
---|---|
Java 문법 정리 8. 다형성 (1) | 2023.10.19 |
Java 문법 정리 7. 상속 (1) | 2023.10.19 |
Java 문법 정리 6. 객체지향 프로그래밍, 클래스 (0) | 2023.10.19 |
Java 문법 정리 **length vs length() vs size() - 길이 값 불러오기 (0) | 2023.10.13 |