前言
在代码的世界里,异常如同旅途中的意外天气,无论准备如何详细,也无法完全避免台风、地震等问题。而异常处理机制,正是让程序从"脆弱易崩"走向"健壮可靠"的关键。Dart为此提供了清晰且灵活的异常管理策略,既能精准捕获错误,又能分层处理,确保应用在复杂场景中依然从容优雅。
一、为什么需要异常处理?
在编程中,说到异常处理,我们第一感觉就是用来提升代码的健壮性和可维护性的,似乎没有啥用,但其实异常处理的作用远远不止于此。我们来逐一说到说到。
- 提升代码的健壮性和可维护性,这我们都知道。
- 防止程序崩溃:未处理的异常会导致程序立即终止,给用户提供了一个不好的体验。使用了异常处理捕获异常不会影响后面程序的运行。
- 确保出现异常时候的资源释放。
- 错误日志记录。便于查找程序出错原因。
二、异常的定义
异常就如同其名字一样,指非正常的情况。是程序运行中的错误或发生的意外情况(如图片加载错误、内存溢出等)。在Dart中使用throw关键字抛出异常,使用try、on、catch、finally关键字捕获并处理异常。
三、异常类型
在Dart中异常使用对象来表示,并将异常分为两类,一类是Error,一类是Exception。
- Error:指程序中发生的严重错误,这类错误通常是不可恢复的,程序会立即终止。例如内存不足引发的错误。
- Exception:指程序中可以预见的异常,这类错误是可进行恢复的。例如网络中断导致的异常。
四、基本语法
4.1、抛出异常
Dart中使用关键字throw抛出异常。
示例:
Dart
int checkAge(int age){
if(age < 0){
throw Exception('$age为负数,年龄不能为负数');
}
return age;
}
4.2、处理异常
使用try、on、catch、finally关键字处理异常。
- try: try大括号包裹的内容为进行检查的代码块,这部分代码通常可以预先知道其可能出现的异常类型。
- on: 用于指定对哪些异常进行捕获(可不指定,不指定时为默认捕获所有类型异常)。
- catch: 捕获指定类型的异常,并获取异常对象。若不用on限定则默认捕获所有类型异常。
- finally: 无论是否捕获到异常都要执行的代码。如关闭数据库等。
示例:
Dart
void main() {
try {
// 可能会有异常的代码
throw Exception('异常');
} on Exception catch (error) {
// 捕获Exception类型的异常,并获取异常对象error,用on限定捕获异常的范围。
print('$error');
} catch (e) {
// 捕获所有类型的异常,并获取异常对象e。
print('未知异常');
}
finally {
// 无论是否异常都会执行的代码。
print('释放资源');
}
}
五、自定义异常
Dart中支持自定义异常的类型,通过继承Exception 或Error创建自定义异常。
示例:
Dart
/// 自定义异常类型CustomException
class CustomException implements Exception{
String? info;
CustomException(this.info);
@override
String toString(){
return '自定义异常:$info';
}
}
// 抛出自定义的异常类型
int checkAge(int age){
if (0 < age && age < 18){
throw CustomException('未满18岁!');
}
return age;
}
// 捕获自定义的异常
void main() {
try{
int currentAge = checkAge(15); // 出现异常。
print('年龄为:$currentAge'); // 不会打印。
} on CustomException catch(error){
print('$error'); // 输出:自定义异常:未满18岁!
}
}
六、异常传播
如果存在函数抛出了异常且没有被捕获,这个异常会向上层调用栈向上传播,直到这个异常被捕获或程序终止。
示例:
Dart
void main() {
try {
dealNum(1, 1); // 调用dealNum函数。
} on CustomException catch (e) {
print('$e'); // 输出:Exception: 分子不能为偶数
} on Exception catch (e) {
print('$e'); // 已经捕获到自定义异常,不打印Exception类型的异常。
} catch (e) {
print('其他异常'); // 已经捕获到自定义异常,不打印其他类型的异常。
} finally {
print('关闭资源'); // 输出:关闭资源
}
}
// dealNum函数中没有进行捕获,会向上层调用栈传播,即向main函数传播。
void dealNum(int a, int b){
int c = 2*a;
int d = 2*b;
divided(c,d); // 调用divided函数
}
// divided函数中抛出异常。
double divided(int a, int b) {
if (b == 0) {
throw CustomException('分母不能为零');
}
if (a % 2 == 0) {
throw Exception('分子不能为偶数');
}
if (a * b == 1) {
throw Error();
}
return a / b;
}
七、异常处理需要注意
- 不应该忽略异常
- 要适度捕获
- 要明确异常类型
八、总结
本小节我们从异常的重要性出发,首先介绍了Dart中异常处理的定义与异常类型,其次了解了Dart中异常处理的基本语法(throw关键词抛出异常,try、on、catch、finally关键字处理异常),然后介绍了自定义异常与异常传播,最后对异常处理的使用进行了建议。