Dart는 안정적인 앱과 서버 사이드 개발을 위해 강력한 예외 처리 메커니즘을 제공합니다. 특히 비동기 작업이 많은 Flutter 환경에서 예외 처리는 필수적인 기술 중 하나입니다. 이 글에서는 Dart에서 예외를 처리하는 다양한 방법과 실전에서 자주 활용되는 패턴, 커스텀 예외 클래스 구현 전략까지 단계적으로 안내합니다.
try-catch-finally 기본 구조
Dart에서 예외 처리는 try-catch-finally
구문을 통해 이루어집니다. Java나 JavaScript의 구조와 유사하지만, Dart에서는 Exception
과 Error
를 구분해서 사용합니다.
void main() {
try {
int result = 10 ~/ 0;
print(result);
} catch (e) {
print('예외 발생: $e');
} finally {
print('항상 실행됨');
}
}
try
블록 안에서 예외가 발생하면 catch
블록으로 제어가 넘어가고, finally
는 예외 발생 여부와 관계없이 무조건 실행됩니다. 정수 나눗셈에서 ~/
연산자는 0으로 나눌 경우 IntegerDivisionByZeroException
을 발생시키며, catch 블록에서 이를 처리할 수 있습니다.
catch
구문은 두 가지 방식으로 작성할 수 있습니다:
// 간단한 예외 메시지 처리
catch (e) { ... }
// 예외 메시지와 StackTrace를 모두 받을 경우
catch (e, stackTrace) { ... }
이러한 예외 처리 구조는 동기 코드뿐 아니라 비동기 async
/await
환경에서도 동일하게 적용됩니다.
비동기 예외 처리 방식
Dart는 비동기 프로그래밍이 활발하게 사용되는 언어이며, 특히 Flutter에서는 API 요청, 파일 IO, 데이터베이스 처리 등 다양한 상황에서 Future
기반 비동기 처리가 사용됩니다. 이때도 예외를 적절히 처리해야 앱이 크래시 되는 것을 방지할 수 있습니다.
Future fetchData() async {
try {
final result = await getDataFromServer();
print(result);
} catch (e) {
print('에러 발생: $e');
}
}
await
키워드를 사용할 경우, 해당 Future가 실패하면 catch
블록으로 이동하게 됩니다. 특히 네트워크 요청, JSON 파싱, 파일 읽기 등에서는 발생 가능한 예외가 많기 때문에 꼭 예외 처리 구문을 포함하는 것이 좋습니다.
또한 Future.catchError()
메서드를 활용하는 방식도 있습니다:
getDataFromServer()
.then((value) => print(value))
.catchError((error) => print('에러: $error'));
이 방식은 콜백 체인을 선호할 때 유용하지만, 일반적으로 가독성과 유지보수 측면에서 async/await
+ try-catch
조합이 추천됩니다. 비동기 흐름에서 예외를 적절히 잡지 않으면 에러 로그만 출력되고 앱이 중단되는 현상이 발생하므로, 항상 예외 방어 코드를 포함해야 합니다.
커스텀 예외 클래스 구현
실무에서는 표준 예외 타입 외에 도메인에 특화된 커스텀 예외를 만들어 사용하는 경우가 많습니다. 예를 들어 사용자 인증 오류, 서버 응답 오류, 로컬 저장소 오류 등을 구분하기 위해 직접 예외 클래스를 구현할 수 있습니다.
class AuthException implements Exception {
final String message;
AuthException(this.message);
@override
String toString() => 'AuthException: $message';
}
이렇게 정의한 예외는 다음과 같이 throw하여 사용할 수 있습니다:
void login(String email, String password) {
if (email.isEmpty || password.isEmpty) {
throw AuthException('이메일과 비밀번호를 입력하세요.');
}
}
예외를 던진 후에는 try-catch
를 통해 해당 예외를 구체적으로 처리할 수 있습니다:
try {
login('', '');
} on AuthException catch (e) {
print(e); // AuthException: 이메일과 비밀번호를 입력하세요.
}
on
키워드를 사용하면 특정 예외 타입만 포착할 수 있어, 예외별로 분기 처리가 가능합니다. 이 방식은 공통 예외 로직과 특수 예외 로직을 분리하는 데 유용하며, Flutter에서는 UI 계층에서 사용자에게 특정 에러 메시지를 전달할 때 자주 사용됩니다.
Dart의 예외 처리 기능은 코드의 안정성과 사용자 경험을 높이는 데 핵심적인 역할을 합니다. 동기/비동기 코드 모두에서 일관된 예외 처리 전략을 적용하고, 필요 시 커스텀 예외 클래스를 활용해 도메인별 예외를 관리하면 더 견고한 애플리케이션을 만들 수 있습니다.