异常
你的Dart代码可以抛出和捕获异常。异常是表示发生了意外情况的错误。如果异常未被捕获,引发异常的隔离区(isolate)会被挂起,通常该隔离区及其程序也会被终止。
与Java不同,Dart的所有异常都是非受检异常(unchecked exceptions)。方法不需要声明它们可能抛出的异常,你也不需要强制捕获任何异常。
Dart提供了Exception和Error类型,以及许多预定义的子类型。当然,你也可以定义自己的异常。不过,Dart程序可以抛出任何非空对象——不仅仅是Exception和Error对象——作为异常。
抛出异常
以下是一个抛出(或引发)异常的示例:
throw FormatException('Expected at least 1 section');你也可以抛出任意对象:
throw 'Out of llamas!';注意
生产环境代码通常抛出实现Error或Exception的类型。
由于抛出异常是一个表达式,你可以在=>语句中抛出异常,也可以在任何允许表达式的地方抛出异常:
void distanceTo(Point other) => throw UnimplementedError();捕获异常
捕获(或截获)异常会阻止异常继续传播(除非你重新抛出异常)。捕获异常让你有机会处理它:
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}如果要处理可能抛出多种类型异常的代码,可以指定多个catch子句。第一个匹配抛出对象类型的catch子句会处理该异常。如果catch子句未指定类型,则该子句可以处理任何类型的抛出对象:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// 特定异常
buyMoreLlamas();
} on Exception catch (e) {
// 其他任何异常
print('Unknown exception: $e');
} catch (e) {
// 未指定类型,处理所有异常
print('Something really unknown: $e');
}如前面的代码所示,你可以使用on、catch或两者结合。需要指定异常类型时用on,异常处理程序需要异常对象时用catch。
你可以为catch()指定一个或两个参数。第一个是抛出的异常,第二个是堆栈跟踪(StackTrace对象)。
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}若要部分处理异常,同时允许它继续传播,可以使用rethrow关键字。
void misbehave() {
try {
dynamic foo = true;
print(foo++); // 运行时错误
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // 允许调用者看到异常
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}finally
为确保无论是否抛出异常都执行某些代码,可以使用finally子句。如果没有catch子句匹配异常,finally子句执行后异常会继续传播:
try {
breedMoreLlamas();
} finally {
// 始终清理,即使抛出异常
cleanLlamaStalls();
}finally子句会在任何匹配的catch子句之后执行:
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // 先处理异常
} finally {
cleanLlamaStalls(); // 然后清理
}如需了解更多,请查阅核心库的异常文档。
断言
在开发过程中,可以使用断言语句——assert(<condition>, <optionalMessage>);——在布尔条件为假时中断正常执行。
// 确保变量不为null
assert(text != null);
// 确保值小于100
assert(number < 100);
// 确保这是https URL
assert(urlString.startsWith('https'));若要为断言附加消息,可将字符串作为assert的第二个参数(可选添加尾随逗号):
assert(
urlString.startsWith('https'),
'URL ($urlString) should start with "https".',
);assert的第一个参数可以是任何解析为布尔值的表达式。如果表达式的值为true,断言成功,程序继续执行;如果为false,断言失败,抛出异常(AssertionError)。
断言何时生效?这取决于你使用的工具和框架:
- Flutter在调试模式下启用断言。
- 仅用于开发的工具(如
webdev serve)通常默认启用断言。 - 某些工具(如
dart run和dart compile js)支持通过命令行标志--enable-asserts启用断言。 - 在生产代码中,断言会被忽略,
assert的参数也不会被求值。