본문 바로가기
  • soobinhand의 기술 블로그
도서/자바 프로그래밍 언어 - James Gosling

[자바 프로그래밍 언어] 12장 예외와 검증

by soobinhand 2021. 12. 31.
728x90

12.1     예외 타입 생성하기

  • 예외는 코드를 어지럽게 하지 않으면서도 오류를 깔끔하게 검사하는 방법을 제공한다. 또한 자바의 예외는 간접적으로 오류 발생 여부를 알아내는 필드를 검사하는 방법이 아닌 직접적으로 오류 발생을 알아내는 방법을 제공하고 있다.
  • 예외는 예상하지 못한 오류가 발생했을 때 던져진다. 그리고 이 예외는 오류를 발생시킨 메소드를 감싸고 있는 예외 처리 코드에 의해 잡힌다. 만약 예외가 잡히지 않았다면 프로그램은 종료된다.
  • 예외는 객체이며 모든 예외 타입은 Throwable 클래스나 이 클래스의 서브 클래스를 확장해야 한다. 
  • 자바의 예외는 대부분이 검증된 예외이다.
  • 새로 작성하는 예외들을 검증된 예외로 만들기 위해서는 Exception을 확장해야만 한다. 이렇게 생성된 검증된 예외는 라이브러리나 애플리케이션에서 발생할 수 있는 예외적인 상태를 나타낸다.
  • 발생한 오류들은 대부분 이미 작성되어 있는 예외들과 매칭시킬 수 있거나, 일반적인 대부분의 오류들은 RuntimeException으로 처리해도 충분.
  • 기억해야 할 것은 검증되지 않은 예외를 올바르게 사용하기 위해서는 문서화를 잘 해야 한다는 것이다. 왜냐하면 컴파일러는 검증되지 않은 예외에 대해서는 어떤 지원도 해주지 않기 때문이다.

12.2     throw 문

  • throw문을 사용하면 예외를 발생시킬 수 있다.
  • throw expression;
  • expression은 Throwable에 대입 가능한 값이나 변수 또는 Throwable 객체의 참조가 되어야 한다.
  • 일단 예외가 발생하면 예외가 발생된 코드 이후의 코드는 실행되지 않는다. 예외가 발생한 뒤 실행될 수 있는 코드는 finally 블록이나 예외를 처리하기 위한 catch 블록이다.
  • throw 문은 숫자를 0으로 나눌 때 발생하는 ArithmeticException 등의 동기 예외를 발생시킬 수 있다. 이 동기 예외는 throw 문이나 숫자를 0으로 나누는 것과 같이 특정 명령어를 직접 실행했을 때 발생하는 반면에, 비동기 예외는 명령문이 실행되는 것과는 상관없이 발생할 수 있다.
  • 비동기 예외는 오직 두 가지 방법에 의해 발생 가능하다.
    • 첫 번째는 JVM 내에서 발생하는 오류이다. 물론 이러한 내부 오류가 발생하면 우리가 할 수 있는 것은 아무것도 없다.
    • 두 번째는 권장되지 않는 Thread.Stop 메소드나 JVM Tool Interface의 stopThread 메소드를 사용하는 경우에 발생한다. 그래서 이러한 메소드는 위험해서 사용하는 것을 권장하지 않는다.

12.3     throws 절

  • 메소드에서 발생할 수 있는 검증된 예외들은 throws 절에 선언할 수 있으며 예외가 여러 개일 경우에는 콤마로 분리해서 선언함. 그리고 throws 절에는 메소드 내에서 잡을 수 없는 예외들만 선언해야 한다.
  • 메소드는 throws 문에 선언되어 있는 검증된 예외들만 발생시킬 수 있기 때문에 throws절에 정의된 협약을 엄격히 지켜야 한다.
  • 메소드에 throws 절이 없더라도 이는 메소드가 어떤 예외도 발생시킬 수 없다는 것을 의미하는 것은 아니다. 단지 검증된 예외를 발생시킬 수 없다는 것을 의미한다.
  • throws 절은 메소드에서 어떤 예외들이 발생할 수 있는지 알려주는 역할과 이 메소드를 호출하는 곳에서 발생한 예외를 처리해야 한다는 것을 명시해주는 역할을 한다.
  • throws 절에는 메소드에서 발생할 수 있는 모든 예외들을 선언해야 한다. 예외들을 구체적으로 모두 명시해서 선언해야 한다. 이것이 문서화를 잘하는 것이다.

12.4     try, catch, finally

  • try 블록을 사용하면 이 블록이 감싸고 있는 코드에서 발생하는 예외를 잡을 수 있다. try 블록의 기본적인 문법은 다음과 같다.
try{
	statements
} catch(exception_1 identifier1){
	statements
} catch(exception_2 identifier2){
	statements
} finally{
	statements
}
  • try 블록을 사용하는 경우에는 catch 절이나 finally 절이 하나는 존재해야 한다. try 문의 몸체는 예외가 발생하거나 몸체의 코드가 성공적으로 종료될 때까지 실행된다. 예외가 발생하면 각각의 catch 절은 발생한 예외 객체 타입이 catch 절에 선언된 예외 타입에 대입 가능한지를 검사한다. 만약 대입 가능한 catch 절이 발견되면 해당 catch 절의 블록은 예외 객체를 참조하는 식별자를 가지고 실행된다. 이때, 다른 catch 절은 실행되지 않는다.
  • 만약 적당한 catch 절을 발견할 수 없으면 예외는 현재 try문을 벗어나 이 예외를 잡을 수 있는 catch 절을 가진 try문으로 전달된다.
  • finally 절이 try문에 존재하면 finally 절의 코드는 try문의 모든 코드가 실행된 이후에 실행된다.
  • try 블록의 모든 코드가 제대로 실행되면 try 블록은 정상적으로 종료되지만, 예외가 throw문에 의해 발생하거나 호출한 메소드에 의해 발생하면 try 블록 내의 코드 실행은 중단된다. 그리고 이 예외를 잡을 수 있는 catch 절이 존재하는지를 검사한다.
  • try 문의 finally 절은 예외가 발생하든 아니든 실행되는 코드 영역이다. 일반적으로 finally절은 내부 상태를 정리하거나 객체가 아닌 자원을 해지하기 위해 사용된다.
  • finally 절을 올바르게 사용하기 위한 두 가지 코딩 방식이 있다. 
    • 첫 번째는 pre와 post라고 불리는 두 가지 행동이 있는 일반적인 경우이다. 예를 들어, pre가 실행된 후에는 post가 실행되어야만 하는 경우이다. 이때 pre와 post 사이의 행동이 무엇이든, 즉 이 행동이 정상적으로 실행되든 예외를 발생하든, 이에 상관없이 post가 실행되어야 한다. 아래 코드와 같다.
pre();
try{
	// other actions...
} finally{
	post();
}
  • 이 코드에서 중요한 것은 pre가 실패하면 post는 실행되지 말아야 하기 때문에 pre를 try문 밖에 위치시켜야 한다는 것이다.
    • 두 번째 방식은 pre가 제대로 실행되었는지 아닌지를 판단할 수 있는 값을 반환한다. pre가 제대로 실행된 경우에만 post가 finally절에서 실행되어야 한다.

12.5     예외 연쇄

  • 예외는 다른 예외에 의해 발생하기도 한다.
  • 예외를 다른 것으로 교체하는 것은 추상화 수준을 높이는 방법이다.

12.6     스택 추적

  • 예외가 생성됐을 때, 호출에 대한 스택 추적은 예외 객체에 저장된다.

12.7     예외는 언제 사용해야 하는가

  • 예상된 상황을 보고하는 방법으로 예외를 남용하지는 말아야 한다.

12.8     검증

  • 검증 (assertion)은 불변성, 즉 항상 진실이 되어야 하는 상태를 검사하기 위해서 사용된다. 검증 결과가 false면 예외가 발생한다.
  • 검증 구문은 다음과 같다.
assert eval-expr [:detail-expr];
  • eval-expr은 boolean이나 Boolean표현식 중 하나여야 하며 detail-expr은 AssertionError 생성자에 전달해 발생한 문제를 설명하기 위한 표현식이므로 생략할 수 있다.

12.9     검증은 언제 사용해야 하는가

  • 검증은 발생할 수 없는 일이 발생할 수 있는지를 통지하기 위해 사용한다. 이것이 검증이 실패했을 때 Exception대신 Error가 발생하는 이유이다. 검증이 실패했다는 것은 현재 상태가 근본적으로 이상하다는 것을 의미한다.
  • 실제로 일어날 수 있는 것이나 일반적인 것을 검사하기 위해 검증을 사용하진 말아야 한다.
  • 사전 조건과 사후 조건 용어는 특정 종류의 상태 검증을 말한다. 사전 조건은 특정 코드 (보통 메소드)가 실행되기 전에 사실이 되어야만 하는 어떤 것이다. 반면 사후 조건은 이 코드 뒤에 사실이어야만 한다.

12.10     검증 활성화와 비활성화

  • 기본적으로 검증 평가는 활성화되어 있지 않다. 
  • 보통 개발 시에는 검증을 활성화하고, 운영 시에는 검증을 비활성화해야 한다. 그래야 개발 주기 동안 오동작을 발견할 수 있다. 
728x90

댓글