해당 포스팅은 톰롱의 Good Code, Bad Code(P. 94~98)를 읽고 정리한 글입니다.
예외
예외는 코드에서 오류나 예외적인 상황이 발생한 경우 이를 전달하기 위한 방법으로 고안되었다. 자바는 검사 예외(Checked Exception)와 비검사 예외(Unchecked Exception)가 있다.
예외가 발생할 때 콜 스택을 거슬러 올라가는데 예외를 처리하는 코드를 만나거나, 더 이상 올라갈 콜 스택이 없을 때까지 그렇게 한다. 더 이상 올라갈 콜 스택이 없는 경우에는 오류 메세지를 출력하고 프로그램이 종료된다.
명시적인 방법 : 검사 예외 (Checked Exception)
컴파일러는 Checked Exception에 대해 호출하는 측에서 반드시 예외를 인지하도록 강제한다. 따라서 호출하는 측에서는 예외를 처리하는 코드를 작성(try-catch)하거나, 메서드 시그니처에 발생 가능한 예외를 선언(throw) 해야 한다. 만약 호출하는 측에서 예외를 처리하지 않으면 컴파일이 불가능하다. Java에서 Exception 클래스를 확장하면 확장된 클래스는 검사 예외가 된다.
검사 예외를 사용한 오류 전달
public class NegativeNumberException extends Exception{ // Exception 을 상속하게 되면 검사 예외가 된다
private final Double erroneousNumber;
NegativeNumberException(Double erroneousNumber){
this.erroneousNumber = erroneousNumber;
}
Double getErroneousNumber(){
return erroneousNumber;
}
}
Double getSquareRoot(Double value) throws NegativeNumberException{ // 함수 시그니처에서 검사 예외를 발생시킬 수 있음을 선언해야 한다.
if(value < 0.0){
throw new NegativeNumberException(value); // 오류가 있을 시 검사 예외를 발생시킨다.
}
return Math.sqrt(value);
}
검사 예외 처리
검사 예외가 발생할 수 있는 함수를 호출하는 코드는 해당 예외를 처리하거나 함수 시그니처에 이 예외를 발생시킬 수 있음을 표시해야 한다.
// 검사 예외 포착
void displaySquarRoot(){
Double value = ui.getInputNumber();
try{
ui.setOutput("Square root is : " + getSquareRoot(value));
}catch (NegativeNumberException e){
ui.setError("Can't get square root of negative number : " + e.getErroneousNumber());
}
}
// 검사 예외 포착하지 않음
void displaySquarRoot() throws NegativeNumberException{
Double value = ui.getInputNumber();
ui.setOutput("Square root is : " + getSquareRoot(value));
}
암시적인 방법 : 비검사 예외(Unchecked Exception)
비검사 예외를 사용하면 다른 개발자들은 코드가 이 예외를 발생시킬 수 있다는 사실을 전혀 모를 수 있다. 따라서 비검사 예외는 오류가 발생할 수 있다는 것을 호출하는 쪽에서 인지하리라는 보장이 없기 때문에 오류를 암시적으로 알리는 방법이다.
비검사 예외를 사용한 오류 전달
public class NegativeNumberException extends RuntimeException{ // RuntimeException 을 상속하게 되면 비검사 예외가 된다
private final Double erroneousNumber;
NegativeNumberException(Double erroneousNumber){
this.erroneousNumber = erroneousNumber;
}
Double getErroneousNumber(){
return erroneousNumber;
}
}
/**
* 어떤 종류의 비검사 예외가 발생할 수 있는지 문서화하는 것이 권장된다.
* @throws NegativeNumberException 값이 음수일 경우
*/
Double getSquareRoot(Double value) {
if(value < 0.0){
throw new NegativeNumberException(value); // 오류가 있을 시 비검사 예외를 발생시킨다.
}
return Math.sqrt(value);
}
비검사 예외 처리
// 비검사 에외도 검사 예외와 똑같은 방식으로 예외를 포착하고 처리할 수 있다.
void displaySquarRoot(){
Double value = ui.getInputNumber();
try{
ui.setOutput("Square root is : " + getSquareRoot(value));
}catch (NegativeNumberException e){
ui.setError("Can't get square root of negative number : " + e.getErroneousNumber());
}
}
중요한 점은 호출하는 함수가 예외를 확인하고 처리하지 않아도 된다는 점이다. 이 경우 예외가 발생하게 되면 예외를 처리하는 코드가 만날 때까지 계속 올라가거나, 끝까지 그 코드가 없으면 프로그램이 종료된다.
// 비검사 예외를 처리하지 않음
void displaySquarRoot(){
Double value = ui.getInputNumber();
ui.setOutput("Square root is : " + getSquareRoot(value));
}
'📚 개발자의 서재 > Good Code, Bad Code' 카테고리의 다른 글
복구 가능성에 따른 적절한 오류 전달 기법 (2) | 2025.02.14 |
---|---|
오류전달기법-2 (0) | 2025.02.13 |
오류를 숨기지 않음 (0) | 2025.02.12 |
견고성 vs 실패 (1) | 2025.02.10 |
Chapter 4 오류 - 복구 가능성 (0) | 2025.02.09 |