IT_Programming/JavaScript

자바스크립트 완벽가이드 - 6.17 try/catch/finally

JJun ™ 2010. 7. 4. 20:49


try/catch/finally 문은 자바스크립트의 예외 처리 기법이다. 이 문장에서 try 절은 그저 처리할 예외가 발생할지도 모를 코드 블록을 정의하는 역할을 한다. try 블록 다음에는 catch 절이 이어진다. catch 절은 try 블록 내부에서 예외가 발생할 경우 호출되는 문장 블록이다. catch 절 다음에는 finally 블록이 이어지는데, 여기에는 앞서 try 블록에서 일어난 일에 관계없이 항상 실행이 보장되어야 할 뒷정리용 코드가 포함된다.

 

catch나 finally 블록은 생략할 수 있다. 하지만 try 블록은 catch나 finally 중 적어도 하나 이상의 블록과 함께 사용되어야만 한다. try, catch, finally 블록은 모두 중괄호로 시작하여 중괄호로 끝난다. 이들 중괄호는 필수로 요구되는 문법의 일부로서 생략할 수 없다. 설사 해당 절에 단 하나의 문장만 있다 하더라도 마찬가지다.

 

throw 문과 유사하게 try/catch/finally 문 역시 ECMAScript v3에서 표준화되고 자바스크립트 1.4에서 구현되었다. 다음 코드에서 try/catch/finally 문의 문법과 용도를 살펴볼 수 있다. 특히 catch 키워드에 뒤따르는

괄호와 그 속의 식별자를 주목하라. 이 식별자는 함수의 전달인자와 닮았다. 이것은 오직 catch 블록의 몸체 내부에서만 존재하는 지역 변수를 명명한다. 앞서 던져진 예외 객체나 값이 무엇이었던 간에 그것이 이 변수에 할당된다.

try {
// 정상이라면 이 코드는 아무런 문제없이 블록의 시작부터 끝까지 수행된다.
// 하지만 경우에 따라 예외가 발생할 수 있다.
// 예외는 throw 문에 의해 직접적으로 발생할 수도 있고,
// 또는 예외를 발생시키는 메서드의 호출에 의해 발생할 수도 있다.
}
catch (e) {
// 이 블록 내부의 문장등은 오직 try 블록에서 예외가 발생할 경우에만 실행된다.
// 이 문장들에서는 지역 변수 e를 사용하여 Error 객체 또는
// 앞에서 던진 다른 값을 참조할 수 있다.
// 이 블록에서는 어떻게든 그 예외를 처리할 수도 있고,
// 그냥 아무것도 하지 않고 예외를 무시할 수도 있고,
// 아니면 throw를 사용해서 예외를 다시 발생시킬 수도 있다.
}
finally {
// 이 블록에는 try 블록에서 일어난 일에 관계없이 무조건 실행될 코드가 위치한다.
// 이 코드는 try 블록이 어떻게든 종료되면 실행된다.
// try 블록이 종료되는 상황은 다음과 같다.
//   1) 정상적으로 블록의 끝에 도달했을 때
//   2) break, continue 또는 return 문에 의해서
//   3) 예외가 발생했지만 앞의 catch 절에서 처리했을 때
//   4) 예외가 발생했고 그것이 잡히지 않은 채 퍼져나갈 때
}


다음에는 try/catch 문에 대한 좀 더 실제적인 예제가 있다. 여기서는 지난 절에서 정의했던 factorial() 메서드를 사용하며, 입출력을 위해 클라이언트 측 자바스크립트 메서드인 prompt()와 alert()를 사용한다.

try {
// 사용자에게 번호 입력을 요청
var n = prompt("Please enter a positive integer","");
// 사용자의 입력이 유효하다고 가정하고
var f = factorial(n);
// 결과를 표시한다.
alert(n +"! =" + f);
}
catch (ex) {  // 만일 사용자의 입력이 유효하지 않다면 이곳에 도달한다.
// 사용자에게 에러가 무엇인지 알린다.
alert(ex);
}


위 코드는 fanally 절이 없는 try/catch 문의 예다. finally는 catch만큼 자주 쓰이는 편은 아니지만 종종 유용할 때가 있다. 하지만 finally의 작동을 이해하려면 추가설명이 필요하다. 일단 try 블록이 일부라도 실행되면 finally 절의 실행은 보장된다. 이때 try 블록의 코드가 어떻게 끝나는지는 상관없다. finally 절은 보통 try 절 코드의 뒷정이를 위해 사용되는 것이 일반적이다.


정상적인 경우 try 블록의 끝까지 프로그램 제어가 도달하고 나면 finally 블록으로 제어가 진행하여 무언가 필요한 뒷정리를 수행한다. 만일 return, continue, break 문 등으로 인해 try 블록에서 제어가 빠져 나왔다면 이들 문장이 인도하는 곳으로 제어가 이동하기에 앞서 finally 블록이 실행된다.


만일 try 블록에서 예외가 발생했는데 거기에 이 예외를 처리하기 위한 catch 블록이 함께 있다면, 제어는 일단 catch 블록으로 이동한 후에 finally 블록으로 넘어온다. 만일 일어난 예외를 처리할 catch가 현 단계에 없다면 일단 finally 블록으로 제어가 이동했다가 그 다음에 상위 단계로 전파되어 올라가서 해당 예외를 처리할 수 있는 가장 가까운 catch 절까지 이동한다.


finally 블록 자체에서 return, continue, break 또는 throw 문을 사용해 제어를 이동시키거나 또는 예외를 발생시키는 메서드를 호출하여 제어를 이동시킬 수도 있다. 이런 경우, finally 블록이 실행된 후에 있을 예정이었던 제어 이동은 취소된다. 그 대신 finally에서 가리키는 새로운 제어 이동이 일어난다. 예를 들어 finally 절에서 예외를 발생시키면 그 예외가, 기존에 발생해서 처리 중이던 예외를 대신한다. 만일 finally 절에서 return 문을 실행했다면, 설사 기존에 예외가 발생했고 아직 미처 처리되지 않았다 하더라도 이 메서드는 정삭적으로 반환된다.


try 와 finally는 catch가 없어도 함께 쓰일 수 있다. 이러한 경우 try 절에서 try, continue, return 문 등이 실행된 것과 관계없이, finally 블록은 그저 무조건 실행이 보장되는 뒷정리 코드의 역할을 한다. 예를 들어 다음의 코드에서는 루프 카운터 변수가 정상적으로 증가될 수 있게 try/finally 문을 사용하고 있다. 설사 continue 문에 의해 루프 반복이 갑자기 끝났다 하더라도 루프 카운터 변수는 증가된다.

var i = 0, total = 0;
while(i < a.length) {
try {
if ((typeof a[i] != "number") || isNaN(a[i])) // 만일 이것이 숫자가 아니라면,
continue;  // 이 루프의 다음 반복으로 넘어간다.
total += a[i];          // 숫자라면 total에 이 숫자를 더한다.
}
finally {
i++;  // 위에서 continue를 썻지만 무조건 i를 증가시킨다.
}
}