Dart 언어에서 예외 처리는 프로그램이 실행 중에 발생할 수 있는 오류나 예외 상황을 처리하기 위해 사용된다. 예외는 예상치 못한 상황을 처리할 수 있는 메커니즘을 제공한다. 예외가 발생했을 때, 프로그램이 바로 종료되는 대신 예외를 처리할 수 있는 코드를 작성함으로써 프로그램의 안정성을 높일 수 있다.
try 블록
try
블록은 예외가 발생할 수 있는 코드를 감싸는 데 사용된다. try
블록 내에서 발생한 예외는 catch
또는 finally
블록에서 처리할 수 있다. try
블록이 완료되면, catch
또는 finally
블록이 실행된다.
try {
// 예외가 발생할 가능성이 있는 코드
}
catch 블록
catch
블록은 try
블록에서 발생한 예외를 처리한다. 예외가 발생하면, 프로그램의 흐름이 try
블록을 중단하고 즉시 catch
블록으로 이동한다. 예외 객체를 사용하여 어떤 종류의 예외가 발생했는지 확인할 수 있다. Dart에서는 catch
블록에 예외 객체와 스택 추적 정보를 받을 수 있다.
catch (e) {
// 예외 처리 코드
}
또한, 예외 객체와 스택 추적 정보를 모두 받을 수도 있다.
catch (e, s) {
// 예외 처리 코드
print('예외: $e');
print('스택 추적: $s');
}
finally 블록
finally
블록은 예외가 발생하든 발생하지 않든 항상 실행되는 코드이다. 예외가 발생하더라도 반드시 실행되어야 할 코드가 있을 때 유용하다. 예를 들어, 파일을 열었다면, 파일을 닫는 작업을 반드시 해야 하는데, 이때 finally
블록에서 해당 작업을 처리할 수 있다.
finally {
// 예외 발생 여부와 상관없이 항상 실행되는 코드
}
이러한 finally
블록은 자원 해제 작업을 포함한 후처리 작업에 주로 사용된다.
전체 예시
다음은 try
, catch
, finally
블록을 모두 사용하는 예시이다:
void main() {
try {
int result = 12 ~/ 0;
print(result);
} catch (e) {
print('예외 발생: $e');
} finally {
print('이 코드는 항상 실행된다.');
}
}
이 코드에서 12 ~/ 0
은 정수 나눗셈이므로, 0으로 나누는 예외가 발생하여 catch
블록으로 이동한다. catch
블록에서 예외를 출력한 후 finally
블록이 실행된다.
예외 흐름 다이어그램
try-catch-finally
의 동작 흐름을 다이어그램으로 나타내면 다음과 같다:
여러 개의 catch
블록
Dart에서는 catch
블록을 여러 개 사용할 수 있으며, 각 블록은 다른 예외 유형을 처리하도록 지정할 수 있다. 이를 통해 더 세부적으로 예외를 처리할 수 있다. Dart의 모든 예외는 Exception
클래스 또는 그 하위 클래스의 인스턴스로 처리된다.
try {
// 예외 발생 가능 코드
} on FormatException {
// 특정 예외 유형 처리 (FormatException)
} catch (e) {
// 다른 모든 예외 처리
}
위 코드는 FormatException
예외가 발생하면 해당 예외를 처리하는 on
블록이 실행되고, 그 외의 다른 예외는 catch
블록에서 처리된다.
on
키워드를 사용하면 예외 유형을 명확하게 지정할 수 있다. 반면, catch
는 모든 예외를 처리하는데 적합한다.
rethrow
를 통한 예외 재발생
때로는 catch
블록에서 예외를 처리한 후, 그 예외를 다시 던져 다른 상위 코드에서 추가로 처리해야 할 때가 있다. 이때 rethrow
키워드를 사용하여 예외를 재발생시킬 수 있다.
try {
// 예외 발생 가능 코드
} catch (e) {
print('예외 처리 중: $e');
rethrow; // 예외를 다시 던짐
}
이 코드는 예외를 한 번 처리한 후, 그 예외를 상위 호출 스택으로 다시 던져 상위 코드에서 추가 처리가 가능하도록 한다.
비동기 함수에서의 예외 처리
비동기 함수에서도 동일한 방식으로 예외 처리를 할 수 있지만, Future
와 함께 사용될 경우에는 await
와 try-catch
를 결합해야 한다. 비동기 함수에서 예외가 발생할 경우, 해당 예외는 Future
객체에 전달되기 때문에 try-catch
블록에서 이를 처리해야 한다.
Future<void> asyncFunction() async {
try {
await someAsyncTask();
} catch (e) {
print('비동기 작업 중 예외 발생: $e');
} finally {
print('비동기 작업 종료');
}
}
비동기 함수에서 발생한 예외도 일반적인 catch
블록에서 처리할 수 있으며, finally
블록은 여전히 작업 완료 후에 실행된다.
예외 처리의 장점
예외 처리는 프로그램의 오류를 우아하게 처리할 수 있도록 하며, 프로그램이 예외로 인해 중단되지 않고 계속 실행되도록 도와준다. 예외 처리를 사용하지 않을 경우, 프로그램은 예기치 않은 오류로 인해 강제 종료될 수 있지만, try-catch-finally
구조를 사용하면 예외 상황을 처리하면서도 프로그램의 흐름을 제어할 수 있다.
다음으로 Dart의 예외 처리에서 유용하게 사용되는 사용자 정의 예외와 예외의 다양한 활용 방법에 대해 다룰 것이다.
사용자 정의 예외
Dart에서는 기본적으로 제공되는 예외 외에도 개발자가 직접 예외를 정의할 수 있다. 이를 통해 특정 상황에서 발생할 수 있는 예외를 세분화하고, 더 명확하게 예외를 처리할 수 있다.
사용자 정의 예외는 Exception
클래스를 상속받아 정의할 수 있다. Exception
클래스는 Dart에서 예외를 처리하는 데 사용되는 기본 클래스이다. 사용자 정의 예외 클래스는 주로 예외 메시지나 추가적인 예외 정보를 담는 필드를 포함할 수 있다.
class CustomException implements Exception {
final String message;
CustomException(this.message);
@override
String toString() => 'CustomException: $message';
}
위의 예제는 CustomException
이라는 사용자 정의 예외를 정의하는 코드이다. toString()
메소드를 재정의하여 예외가 발생했을 때 출력될 메시지를 지정할 수 있다.
사용자 정의 예외를 사용하여 예외를 발생시키는 예는 다음과 같다.
void validateInput(int input) {
if (input < 0) {
throw CustomException('입력 값은 음수가 될 수 없다.');
}
}
throw
키워드를 사용하여 예외를 발생시킬 수 있으며, 이 예외는 try-catch
블록으로 처리된다.
void main() {
try {
validateInput(-1);
} catch (e) {
print(e);
}
}
이 코드는 validateInput(-1)
을 호출하여 예외를 발생시키고, catch
블록에서 해당 예외를 처리한다. 출력 결과는 다음과 같이 나타난다.
CustomException: 입력 값은 음수가 될 수 없다.
이처럼 사용자 정의 예외는 특정 도메인이나 비즈니스 로직에 맞는 예외 처리를 가능하게 하여, 코드의 가독성을 높이고, 문제를 보다 쉽게 디버깅할 수 있다.
예외 객체의 추가 정보 포함
때로는 예외 객체에 추가적인 정보를 포함시켜야 할 때가 있다. Dart에서는 이를 위해 예외 객체에 필요한 데이터를 전달할 수 있다. 예를 들어, 오류 코드나 관련 데이터를 함께 제공함으로써 예외 상황을 더 구체적으로 설명할 수 있다.
class DetailedException implements Exception {
final String message;
final int errorCode;
DetailedException(this.message, this.errorCode);
@override
String toString() => 'Error $errorCode:$message';
}
이 예제에서는 errorCode
라는 필드를 추가하여 예외의 구체적인 오류 코드를 함께 전달할 수 있다. 이를 통해 예외 상황을 더욱 구체적으로 파악할 수 있다.
void main() {
try {
throw DetailedException('파일을 찾을 수 없다.', 404);
} catch (e) {
print(e);
}
}
이 코드는 다음과 같은 결과를 출력한다:
Error 404: 파일을 찾을 수 없다.
이와 같은 방식을 사용하면 예외 처리 시 추가적인 정보를 제공할 수 있어, 문제를 디버깅하고 해결하는 데 도움이 된다.