[Dart 언어강좌] 023. Dart에서의 에러 처리, try-catch-finally 구문

들어가며

Dart는 현대적인 객체 지향 프로그래밍 언어로서, 코드의 안전성을 높이기 위한 다양한 기능을 제공합니다.
그중 하나는 에러 처리입니다. 에러를 효율적으로 처리하는 것은 안정적인 애플리케이션 개발에 필수적입니다.
에러 처리를 통해 개발자는 예상치 못한 상황에서도 프로그램이 비정상적으로 종료되는 것을 방지할 수 있습니다.
이번 글에서는 Dart에서 에러를 처리하는 방법, 특히 try-catch-finally 구문에 대해 살펴보겠습니다.

1. Dart의 에러 처리 개념

Dart에서 에러는 런타임 중에 발생할 수 있는 문제입니다.
예를 들어, 파일을 읽으려고 할 때 해당 파일이 존재하지 않을 수 있습니다.
이처럼 프로그램의 흐름을 방해하는 다양한 상황이 있습니다.
Dart는 이를 처리하기 위해 try, catch, finally 구문을 제공합니다.

2. try-catch 구문

try 블록 내의 코드는 정상적으로 실행될 경우 에러가 발생하지 않습니다.
그러나 에러가 발생하면, 해당 블록의 실행이 중단되고 catch 블록으로 넘어갑니다.
catch 블록에서는 발생한 에러를 처리할 수 있습니다.
다음은 간단한 예제입니다.


void main() {
    try {
        int result = 10 ~/ 0;  // 0으로 나누기 시도
        print(result);
    } catch (e) {
        print('에러 발생: $e');
    }
}
        

위의 예제에서 ~/ 연산자는 정수 나누기를 수행합니다.
0으로 나누기를 시도할 때, 프로그램은 에러를 발생시키고, catch 블록이 실행됩니다.
결과적으로 “에러 발생: IntegerDivisionByZeroException”이라는 메시지가 출력됩니다.

3. 특정 에러 처리

catch 블록에서는 특정 타입의 에러를 처리할 수도 있습니다.
이를 통해 보다 구체적인 에러 처리 로직을 구현할 수 있습니다.
다음은 그러한 예제입니다.


void main() {
    try {
        int result = 10 ~/ 0;  // 0으로 나누기 시도
        print(result);
    } on IntegerDivisionByZeroException catch (e) {
        print('0으로 나누지 마세요: $e');
    } catch (e) {
        print('다른 에러 발생: $e');
    }
}
        

위의 코드에서는 먼저 IntegerDivisionByZeroException 타입의 에러를 처리하고,
그 외의 다른 에러는 일반적인 catch 블록으로 처리합니다.
이렇게 특정 에러를 분리하여 처리하는 것이 가능한 점이 Dart의 장점 중 하나입니다.

4. finally 구문

finally 블록에서는 trycatch 블록의 실행 여부와 상관없이 항상 실행되는 코드를 작성할 수 있습니다.
주로 리소스를 정리하는 데 사용됩니다. 아래는 finally 블록의 예제입니다.


void main() {
    try {
        int result = 10 ~/ 0;  // 0으로 나누기 시도
        print(result);
    } catch (e) {
        print('에러 발생: $e');
    } finally {
        print('리소스 정리 작업 실행.');
    }
}
        

여기서 “리소스 정리 작업 실행.” 메시지는 에러 발생 여부에 관계없이 항상 출력됩니다.
이는 파일 핸들링, 데이터베이스 연결 등을 종료하는 데 유용합니다.

5. 여러 개의 catch 블록 사용하기

Dart에서는 여러 개의 catch 블록을 사용하여 다양한 에러 타입을 처리할 수 있습니다.
다음은 이러한 예제를 보여줍니다.


void main() {
    try {
        int result = 10 ~/ 0;  // 0으로 나누기 시도
        print(result);
    } on FormatException catch (e) {
        print('형식 오류: $e');
    } on IntegerDivisionByZeroException catch (e) {
        print('0으로 나누기: $e');
    } catch (e) {
        print('일반적인 에러 발생: $e');
    } finally {
        print('작업 완료');
    }
}
        

여기서는 FormatExceptionIntegerDivisionByZeroException을 각각 특정적으로 처리하고 있습니다.
다른 모든 에러는 마지막의 일반적 catch 블록으로 처리됩니다.

6. 사용자 정의 에러 만들기

Dart에서는 사용자 정의 에러 클래스를 만들어 특정한 조건에 대한 에러를 발생시킬 수 있습니다.
다음 예제를 통해 알아보겠습니다.


class CustomError extends Error {
    final String message;
    CustomError(this.message);
}

void checkValue(int value) {
    if (value < 0) {
        throw CustomError('값은 0보다 커야 합니다.');
    }
}

void main() {
    try {
        checkValue(-10);
    } catch (e) {
        print('사용자 정의 에러 발생: $e');
    }
}
        

위의 예제에서 checkValue 함수는 매개변수로 받은 값이 0보다 작을 경우
CustomError를 발생시킵니다.
catch 블록에서 이 사용자 정의 에러를 처리합니다.

7. 비동기 에러 처리

Dart에서는 비동기 프로그래밍을 지원하며, 여기에 대한 에러 처리 또한 가능합니다.
Futureasync/await를 사용할 때의 에러 처리 방법을 살펴보겠습니다.


Future main() async {
    try {
        await futureWithError();
    } catch (e) {
        print('비동기 에러 발생: $e');
    }
}

Future futureWithError() async {
    throw Exception('비동기 작업 중 에러 발생');
}
        

위의 코드에서는 비동기 함수 futureWithError가 에러를 발생시키고,
이를 main 함수에서 try-catch로 처리합니다.
비동기 작업에서도 에러 처리는 동일한 방식으로 진행됩니다.

결론

Dart에서 에러 처리는 코드의 안정성을 보장하는 데 필수적인 요소입니다.
try-catch-finally 구문을 통해 에러를 효율적으로 처리할 수 있으며,
다양한 상황에 맞춰 사용자 정의 에러, 비동기 에러 처리 방법까지 지원합니다.
이를 통해 개발자는 더욱 견고한 애플리케이션을 개발할 수 있습니다.

이번 글을 통해 Dart에서의 에러 처리 방법에 대해 이해하고 활용할 수 있기를 바랍니다.
에러 처리를 통해 프로그램의 신뢰성을 높이고, 사용자에게 더 나은 경험을 제공하는 개발자가 되시길 바랍니다.