#1. 예외처리

1. 예외처리(Exception Handling)란?

  • 프로그램 실행 중 예기치 못한 에러가 발생했을 때 대처할 수 있게 처리하는 것을 뜻한다.
  • Syntax Error: 구문오류. 코딩상의 실수이므로 수정하지 않으면 프로그램이 동작하지 않는다. (단순 오타)
  • Runtime Error: 프로그램 작성 과정에서 논리상의 오류로 미쳐 대응하지 못한 상황이 발생하는 경우이다.
    • 프로그램이 실행되다가 오류나는 부분을 만나면 멈춘다.

 

2. 기본(고전적) 예외처리

  • 조건문을 사용하는 기본(고전적) 예외처리이다.
  • 프로그램이 실행되기에 적합하지 않는 파라미터가 전달 된 경우 미리 약속된 값을 리턴한다
    • 프로그램의 성공 / 실패 여부를 리턴값으로 판단하는 경우이다.
function example(x, y) {
  if(x < 0 && y < 0) {
    return 0
  }
  return x + y;
};

// 비정상인 상황에 대한 고전적 처리
const ex = example(-1, -2);  // 비정상적인 호출

// 에러 상황에 대한 대응(메세지 처리)을 함수를 호출하는 곳에서 해야한다.
if(ex == 0) {
  console.log("0보다 작으면 안됩니다.");
} else {
  console.log(ex);
}

 

2. try - catch

  • try 구문안에서 예외가 발생하면, catch 구문으로 넘어가 처리하는 방식이다.
  • 반대로 try 구문안에서 예외가 발생하지 않는다면 catch 구문은 건너뛴다. (try - catch는 한쌍)
  • catch( ) 는 무슨 에러가 발생했는지에 대한 설명이 담긴 객체이다.
  • try - catch 문을 사용하면 에러가 발생해도 프로그램이 중단되지 않는다.
  • finally 구문도 있는데, 에러의 발생 여부에 상관없이 마지막에 실행되는 구문이다.
    • 필요하지 않는 경우 생략해도 된다.
// 변수 선언
const data = [1, 2, 3];

try {
  for(let i = 0; i < 10; i++) {
  	console.log(data[i].toFixed(2)); // toFixed 할 배열 수 부족, 에러발생
  }

  // 에러가 발생하면 에러난 코드 밑으로는 실행되지 않는다.
  console.log("try 블록 실행완료");  // 실행 안됨

} catch(err) {  // ( )안에는 아무 이름을 넣어도 된다.
  console.log(err);  // 예외 정보 전체가 출력된다.
  console.log(err.name);  // 예외 이름
  console.log(err.message);  // 예외 메세지
  console.log(err.description);  // 예외 설명

} finally {  // 생략가능
  console.log("배열 탐색 종료");
}

// try-catch문을 사용하면 에러가 발생하더라도 프로그램이 중단되지 않는다.
console.log("프로그램 종료");

 

3. throw

  • 직접 에러를 발생시킬 때 사용할 수 있다.
  • 이 구문을 실제 에러로 인식하기 때문에 프로그램이 이 위치에서 중단된다.
    • throw 밑에 있는 코드는 실행되지 않는다.
// 에러 객체를 생성
// 생성자 파라미터로 에러의 내용 전달
let err = new Error("에러났는데요?");
console.log(err.name);  // Error(에러 객체 이름)
console.log(err.message);  // 에러났는데요?(에러 객체 메세지)

// 개발자가 직접 에러를 발생시킬 수 있다.
throw err;

// 실행 안됨
console.log("프로그램 종료");
  • throw 구문은 try - catch로 처리가 가능하다.
let err = new Error("에러났는데요?");

try {
  // try 구문안에 throw를 넣어 에러 발생시킨다.
  throw err;

} catch(err) {
  console.log(err.name);  // Error(에러 객체 이름)
  console.log(err.message);  // 에러났는데요?(에러 객체 메세지)
}

// 에러 상황을 try-catch로 처리했기 때문에 프로그램이 중단되지 않고 무사히 종료 할 수 있다.
console.log("프로그램 종료");  // 프로그램 종료

 

4. 예외객체를 활용한 예외처리

function example(x) {
  if(x < 0) {
    // 함수 안에서 에러를 강제로 발생시킬 경우, 이 함수를 호출하는 위치를 에러로 인식한다.
    throw new Error("x가 0보다 작습니다.")  // 파라미터로 에러 메세지 전달
  }
  return x;
}

// a에 null 값 대입
// 에러 점검이 끝난 후 try-catch 블록 밖에서 a의 값을 활용하려면 변수의 선언 위치가 try 블록보다 위에 있어야 한다. (변수의 스코프 규칙)
let a = null;

// try 블록 안의 코드는 최소화 하는 것이 프로그램 효율에 좋다. (결과 값은 try 블록 밖에서 사용하는것이 좋다.)
try {

  // 0보다 작은 값 전달
  // 호출 에러이기 때문에 대입이 안된다. (대입전에 에러)
  a = example(-1);

} catch (err) {
  // catch 구문으로 전달 되는 err 객체는 위 함수에서 생성한 Error 클래스의 객체이다.
  console.log(err.name);  // Error
  console.log(err.message);  // x가 0보다 작습니다
}

console.log(a);  // null

 

5. 사용자정의 에러

  • 에러의 종류를 세분화 하기 위해 Error 클래스의 기능을 상속(확장) 받아 직접 에러에 대한 경우의 수를 정의할 수 있다.
  • 자식클래스가 생성자를 갖는 경우 부모의 생성자를 반드시 강제 호출해야한다.
class X_Small extends Error {
  // 자식클래스가 생성자를 갖는 경우 부모의 생정자를 반드시 강제 호출해야한다. (super)
  constructor(msg) {
    super(msg);
    super.name = "에러발생! x가 0보다 작은데요?"  // 에러 이름 대입
  }
}
class Y_Small extends Error {
  constructor(msg) {
    super(msg);
    super.name = "에러발생! y가 0보다 작은데요?"  // 에러 이름 대입
  }
}

function example(x, y) {
  if(x < 0) {
    throw new X_Small("x가 0보다 작습니다.");  // 에러 메세지 전달
  }
  if(y < 0) {
    throw new Y_Small("y가 0보다 작습니다.");  // 에러 메세지 전달
  }
  return x + y;
}

let a = null;
let b = null;

try {
  a = example(-1, 1);

} catch (err) {
  console.log(err.name);  // 에러발생! x가 0보다 작은데요?
  console.log(err.message);  // x가 0보다 작습니다.
}

try {
  b = example(1, -1);

} catch (err) {
  console.log(err.name);  //에러발생! y가 0보다 작은데요?
  console.log(err.message);  // y가 0보다 작습니다
}

console.log(a);  // null
console.log(b);  // null

 

6. 모듈을 활용한 예외처리

Error 클래스를 상속받아 사용자정의 에러 클래스를 만들고, 모듈을 통해 예외처리를 할 수 있다.

※ 입력값 검사하는 예외처리 예시

  • Error 클래스를 상속받아 자식클래스를 확장시키고, 모듈에 등록한다
// Error 클래스를 상속
class BadRequestException extends Error {
  // 자식클래스가 생성자를 갖는 경우 부모의 생성자를 호출해야 한다.
  constructor(msg = "잘못된 요청 입니다.") {  // 파라미터로 받는 값이 없으면 기본값 리턴
    // 부모의 생성자 호출
    super(msg);
    // 부모 멤버변수 변환
    super.name = "BadRequestException";

    // 자식클래스에서 멤버변수 추가
    this._statusCode = 400;
  }

  // gettter로 statusCode 값 반환
  get statusCode() {
    return this._statusCode;
  }
};

// 모듈 생성
module.exports = BadRequestException;
  • Error 클래스를 상속받아 확장된 자식클래스를 모듈을 통해 호출하여 입력값을 검사할 클래스를 만든다.
// 자식클래스 모듈 호출
const BadRequestException = require("./ex_BadRequestException");

// 검사할 클래스 생성
class RegexHelper {
  // 메서드 생성
  // 파라미터로 받는 input 값은 test 파라미터로, msg 값은 BadRequestException 파라미터로 보낸다.
  kor(input, msg) {
    // 정규표현식 체크하는 변수 생성(영문+한글)
    const check = /^[a-zA-Zㄱ-ㅎ가-힣]*$/;
    // .test()를 통해 검사, 파라미터로 받은 값이 정규표현식이 아니라면 강제로 에러 발생
    if(!check.test(input)) {
      throw new BadRequestException(msg);  // BadRequestException 객체 생성
    }
  }
}

// 모듈 생성
module.exports = RegexHelper;
  • try-catch문으로 입력값을 검사한다.
  • 입력값이 true면 catch 구문을 무시하고, 입력값이 잘못되면 catch 구문 실행한다.
// 검사하는 클래스 모듈 호출
const RegexHelper = require("./ex_RegexHelper");

// 사용자가 입력한 값
const username = "Java스크립트123";  // 잘못된 값 입력

// 입력값 검사를 수행하기 위한 객체 생성
const regex = new RegexHelper();

try {
  // RegexHelper 클래스의 kor() 메서드에 파라미터 값 전달
  regex.kor(username, "영문과 한글만 입력하세요.")
} catch(err) {
  console.error("%s 에러 발생", err.name);  // BadRequestException 에러 발생
  console.error("에러코드: %d", err.statusCode);  // 에러코드: 400
  console.error("에러내용: %s", err.message);  // 에러내용: 영문과 한글만 입력하세요.
} finally {
  console.log("검사완료");
}

 

7. 비동기 예외처리

  • try-catch는 동기 방식으로 동작하기 때문에 비동기 방식으로 동작하는 코드에는 대응하지 못한다. (timer, ajax 등등)
  • 콜백함수를 받아 처리하는 setTimeout( )의 경우, try-catch는 콜백함수 안까지 관여하지 못한다.
const example = [1,2,3];

try {
  setTimeout(() => {
    // 콜백함수 안까지는 try-catch가 관여하지 못한다.
    for(let i = 0; i < 10; i ++) {
      console.log(example[i].toFixed(2));
    }

    // 위에서 에러가 발생했기 때문에 실행되지 않는다.
    console.log("배열탐색 종료");
  }, 1000)  // 1초 뒤 실행되다가 에러가 나는 부분부터 중지된다.
} catch(err) {
  // catch 구문도 비동기 함수는 처리하지 못하기 때문에 실행되지 않는다.
  console.log("에러발생");
}

// 가장 먼저 실행된다.
console.log("프로그램 종료");
  • 비동기 방식을 예외처리 하기 위해서는 콜백함수 내부에서 처리해야한다. (try-catch 문을 넣어야 한다.)
const example = [1,2,3];

setTimeout(() => {
  // 콜백함수 내부에 try-catch 선언
  try {
    for(let i = 0; i < 10; i++) {
      console.log(example[i].toFixed(2));
    }

    // 위에서 에러가 발생했기 때문에 실행되지 않는다.
    console.log("배열탐색 종료");

  } catch(err) {
    // try 구문에서 에러가 발생했기 때문에 catch 구문 실행
    console.log("에러발생");  // 에러발생
    console.error(err.name);  // TypeError
    console.error(err.message);  // 에러 메세지 내용
  }
  // 콜백함수 내부에서 처리된 예외처리는 발생한 에러 상황을 처리할 수 있기 때문에 아래의 코드는 정상적으로 실행
  console.log("배열탐색 종료2");
}, 1000);

// 가장 먼저 실행된다.
console.log("프로그램 종료");

+ Recent posts