Copyright (c) 2015-, All Rights Reserved by Kwanghoon Choi
(아래 자바 프로그래밍 강의 교재의 내용을 자유롭게 이용하되 다른 웹 사이트 등을 통한 배포를 금합니다.)
3. 예외 처리 응용
Mazi 해석기에 예외 처리를 적용해 보자.
Mazi 해석기에서 발생할 수 있는 에러는 다양하다. 예를 들어,
- evalExpr(int operand1, String operator, int operand2) 메소드에서 지정한 연산자를 지원하지 않을 때 (+, -, *, / 이외의 연산자)
- evalStmt(HashMap<String,Integer> env, StringTokenizer stz) 메소드에서 stz의 토큰의 수가 0일때
- 할당문의 = 연산자를 잘못 지정할 때 (예를 들어, x = 123 대신 x := 123)
- 기타 등등
이전 Mazi 해석기에서 이러한 에러가 발생하면 해당 에러 상황에 대한 메시지를 표준 에러(System.err)에 출력하고, 만일 리턴값이 필요한 경우에는 무조건 0을 리턴 해서 처리했다. 나열한 모든 에러는 발생 가능성을 예측 가능하고 그 에러의 원인은 프로그램 내부에 있다. 따라서 검사 예외를 두어 처리하는 것이 바람직하다.
class MaziException extends Exception { private String msg; // msg를 지정하는 생성자 // msg에 대한 getter 메소드 }
Mazi 해석기에서 표준 에러로 출력하거나 에러를 내는 대신 0을 리턴한 코드를 모두 throw new MaziException( ... 상황별 에러 메시지 ...)로 대체할 수 있다. 예를 들어, evalExpr(int operand1, String operator, int operand2) 메소드의 switch문 default 경우에 다음과 같이 수정한다.
switch ( operator.charAt(0) ) { case '+': ... case '-': ... case '*': ... case '/': ... default: // System.err.println("Unsupported operator: " + operator); throw new MaziException("Unsupported operator: " + operator); }
evalExpr 메소드 내부의 switch 문에서 발생한 MaziException 예외를 어디에서 처리하면 좋을까? 여러가지 방법이 가능하지만 main 메소드에서 이 예외를 포함해서 다른 메소드나 코드에서 발생한 예외까지 일괄적으로 처리한다고 가정하자. 이 설계에 의하면 evalExpr 메소드 내부에 try/catch 문을 두기 보다 예외 명세를 선언하는 방식으로 처리해야 한다.
public static int evalExpr(int operand1, String operator, int operand2) throws MaziException { ... switch ( operator.charAt(0) ) { ... default: throw new MaziException("Unsupported operator: " + operator); } ... }
main 메소드는 다음과 같이 수정 가능하다.
public static void main(String[] args) { ... while ( scanner.hasNext() ) { String line = scanner.nextLine(); StringTokenizer stz = new StringTokenizer(line); if (stz.countTokens() > 0) { try { evalStmt(env, stz); } catch(MaziException exn) { System.err.println(exn.get()); } } } }
입력 받은 줄에서 예외가 발생하면 표준 에러에 그 내용을 출력하고 다시 Mazi 해석기를 진행하는 방식으로 처리한다.
[연습문제] Mazi 해석기에 예외 처리를 추가하시오.