Dart 所有异常都是非检查异常,不用函数声明抛出类型,不强制捕获
两类:
Exception:业务逻辑可预期错误(格式、参数等,建议捕获处理)Error:程序致命错误(类型错误、空指针、未实现等,一般不捕获)
任意非 null 对象都能 throw,规范项目只抛 Exception/Error 子类
未捕获异常会终止当前隔离区(isolate),程序崩溃
throw 抛出异常
1. 抛系统内置异常
void main() {
// 格式异常
throw FormatException("至少需要1段数据");
}
Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
FormatException: 错误描述
#0 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:3:3)
#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)
以上代码,就抛出一个你自己定义的异常,你可以自己写描述,执行的时候会报错,也许你会觉得这代码有什么用?但是其实抛出异常是很重要的,例如用户注册的时候,要验证用户输入是否规范,如果不规范,就直接提示错误,这个时候,可以直接抛出异常,告诉用户出错了,这样避免不对的数据污染,保证数据规范。
2. 抛出任意对象
不推荐生产环境
void main() {
throw "文字描述!";
}Code language: Dart (dart)
执行结果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
文字描述!
#0 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:2:3)
#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)
3. 箭头函数内 throw(throw 是表达式)
class Point {}
void distanceTo(Point other) => throw UnimplementedError("该方法未实现");
void main() {
distanceTo(Point());
}
Code language: JavaScript (javascript)
三、try /on/catch 捕获异常
语法区分
on 异常类型:只匹配指定类型异常,拿不到异常对象catch(e):捕获所有异常,拿到异常实例 ecatch(e, s):e = 异常对象,s = 堆栈信息 StackTrace
1:指定单一异常捕获 on
//自定义一个异常类 继承Exception
class OutOfLlamasException implements Exception {}
//抛出上面自定义的异常
void breedMoreLlamas() {
throw OutOfLlamasException();
}
void buyMoreLlamas() {
print("执行了buyMoreLlamas");
}
void main() {
try {
breedMoreLlamas(); //调用函数 执行这里
} on OutOfLlamasException {
buyMoreLlamas(); //如果捕捉到OutOfLlamasException异常 就执行这里
}
}Code language: Dart (dart)
执行结果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
执行了buyMoreLlamasCode language: CSS (css)
try {
//你认为会报错的代码
} on excetion {
//如果捕捉到错误 执行的代码
}Code language: Dart (dart)
try on 的只是一个捕捉异常的写法。
2:多分支分层捕获
精准匹配优先
class OutOfLlamasException implements Exception {}
void breedMoreLlamas() {
throw FormatException("数据格式错误");
}
void main() {
try {
breedMoreLlamas();
}
// 1. 精准匹配自定义异常
on OutOfLlamasException {
print("OutOfLlamasException 出错了");
}
// 2. 匹配所有Exception子类
on Exception catch (e) {
print("普通业务异常:$e");
}
// 3. 兜底捕获Error、任意其他对象
catch (e) {
print("未知严重错误:$e");
}
}
Code language: Dart (dart)
输出 : 普通业务异常:FormatException: 数据格式错误
可以通过多个on 来具体捕捉某个Exception。还可以使用catch 来兜底。
3:捕获异常 + 打印堆栈 StackTrace
void main() {
try {
int a = null;
print(a + 1);
} catch (e, stack) {
print("异常信息:$e");
print("完整堆栈:\n$stack");
}
}
Code language: Dart (dart)
以上代码 不仅仅输出异常提示,还可以把代码调用的堆栈也输出出来
D:\dartdemo\firstdart>dart run
Building package executable...
Failed to build firstdart:firstdart:
bin/firstdart.dart:3:13: Error: A value of type 'Null' can't be assigned to a variable of type 'int'.
int a = null;Code language: PHP (php)
四、rethrow
部分处理,继续向上抛出
作用:当前函数处理一部分逻辑,再把异常抛给上层调用者捕获
有些时候,我们不仅仅代码中处理异常,可能还会再往上(调用的地方)抛出异常,希望往上再处理一下。
void misbehave() {
try {
dynamic foo = true;
print(foo++); // true不能自增,运行时报错
} catch (e) {
print("misbehave 局部处理:${e.runtimeType}");
rethrow; // 重新抛出,交给外层try
}
}
void main() {
try {
misbehave();
} catch (e) {
print("main 最终处理:${e.runtimeType}");
}
}
Code language: Dart (dart)
执行过程:
misbehave 局部处理:NoSuchMethodError
main 最终处理:NoSuchMethodError
上面代码不仅仅在misbehave函数中处理,还在main函数中也处理了
五、finally 最终块
无论是否报错一定执行
两种场景:
- 只有 try + finally:报错不捕获,执行完 finally 后程序崩溃
- try + catch + finally:先处理异常,再执行 finally(资源释放专用)
1:try + finally
void cleanLlamaStalls() => print("清理资源,兜底用的(必定执行)");
void breedMoreLlamas() => throw Exception("出错了");
void main() {
try {
breedMoreLlamas();
} finally {
cleanLlamaStalls();
}
}
Code language: Dart (dart)
执行结果,下面虽然执行了代码,但是最终都抛出了异常了。
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
清理资源,兜底用的(必定执行)
Unhandled exception:
Exception: 出错了
#0 breedMoreLlamas (file:///D:/dartdemo/firstdart/bin/firstdart.dart:2:27)
#1 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:5)
#2 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#3 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)
2:try + catch + finally
资源释放标准写法,例如打开文件的是,要释放
void cleanLlamaStalls() => print("关闭文件/释放资源");
void breedMoreLlamas() => throw FormatException("解析失败");
void main() {
try {
breedMoreLlamas();
} catch (e) {
print("捕获异常:$e");
} finally {
cleanLlamaStalls();
}
}
Code language: Dart (dart)
执行顺序:触发异常 → catch 处理 → finally 执行
执行结果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
捕获异常:FormatException: 解析失败
关闭文件/释放资源
六、assert 断言
仅开发调试,生产直接失效
assert(布尔条件, [可选错误提示])
条件为 false 抛出 AssertionError;生产环境完全忽略,不执行。
1:基础断言
void main() {
String? text;
int number = 120;
String url = "http://foxdevelop.com";
assert(text != null); // 校验非空
assert(number < 100); // 数值范围校验
assert(url.startsWith("https")); // 链接协议校验
}
Code language: JavaScript (javascript)
以上代码执行,但是什么都没有输出!
原因是你需要开启的,否则默认是不启用断言的,继续往下看
2:自定义错误信息
void main() {
String url = "http://test.com";
assert(
url.startsWith("https"),
"链接 $url 必须以 https 开头",
);
}
Code language: JavaScript (javascript)
我们可以把断言失败的提示信息,自己来定义的。
启用断言方式
- Flutter Debug 模式默认开启
- dart 命令运行:
dart --enable-asserts 你的dart文件名.dart - 生产打包:断言全部移除,无性能损耗
D:\dartdemo\firstdart\bin>dart --enable-asserts firstdart.dart
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)
dart run 和 dart 命令一样,默认关闭断言,需要追加 --enable-asserts 参数:
运行
dart run --enable-asserts main.dartCode language: CSS (css)
如果终端已经在项目目录,直接:
运行
dart run --enable-asserts
dart run:直接运行 Dart 源码,适合开发调试
dart 文件名:等价简易运行
dart compile exe:编译二进制成品,编译产出永远禁用 assert
我们回到bin目录是上一级,你的dart文件是在bin目录的,cd到bin目录的上一级, 执行
dart run –enable-asserts
如下第一个是,直接到bin目录执行 dart的文件,第二个是在上级目录 ,项目根目录执行。
D:\dartdemo\firstdart\bin>dart --enable-asserts firstdart.dart
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)
D:\dartdemo\firstdart\bin>dart run
Building package executable...
Built firstdart:firstdart.
D:\dartdemo\firstdart\bin>cd ..
D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)
如果断言是true的话,就不会抛出异常
上面代码改为 String url = “https://foxdevelop.com”; http改为https,text != null 改为==,number = 99
void main() {
String? text;
int number = 99;
String url = "https://foxdevelop.com";
assert(text == null); // 校验非空
assert(number < 100); // 数值范围校验
assert(url.startsWith("https")); // 链接协议校验
}Code language: Dart (dart)
再次执行 没有抛出异常
D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.Code language: CSS (css)
七、例子
void cleanResource() => print("finally:释放资源");
void testError() {
try {
int num = 150;
assert(num < 100, "数字必须小于100");
throw FormatException("数据格式非法");
} on FormatException catch (e) {
print("捕获格式异常:$e");
rethrow;
} finally {
cleanResource();
}
}
void main() {
try {
testError();
} catch (e) {
print("main 捕获二次抛出的异常:$e");
}
}
Code language: PHP (php)
执行结果
D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.
finally:释放资源
main 捕获二次抛出的异常:'file:///D:/dartdemo/firstdart/bin/firstdart.dart':
Failed assertion: line 6 pos 12: 'num < 100': 数字必须小于100Code language: PHP (php)