Skip to content

异常

你的Dart代码可以抛出和捕获异常。异常是表示发生了意外情况的错误。如果异常未被捕获,引发异常的隔离区(isolate)会被挂起,通常该隔离区及其程序也会被终止。

与Java不同,Dart的所有异常都是非受检异常(unchecked exceptions)。方法不需要声明它们可能抛出的异常,你也不需要强制捕获任何异常。

Dart提供了ExceptionError类型,以及许多预定义的子类型。当然,你也可以定义自己的异常。不过,Dart程序可以抛出任何非空对象——不仅仅是ExceptionError对象——作为异常。

抛出异常

以下是一个抛出(或引发)异常的示例:

dart
throw FormatException('Expected at least 1 section');

你也可以抛出任意对象:

dart
throw 'Out of llamas!';

注意
生产环境代码通常抛出实现ErrorException的类型。

由于抛出异常是一个表达式,你可以在=>语句中抛出异常,也可以在任何允许表达式的地方抛出异常:

dart
void distanceTo(Point other) => throw UnimplementedError();

捕获异常

捕获(或截获)异常会阻止异常继续传播(除非你重新抛出异常)。捕获异常让你有机会处理它:

dart
try {
  breedMoreLlamas();
} on OutOfLlamasException {
  buyMoreLlamas();
}

如果要处理可能抛出多种类型异常的代码,可以指定多个catch子句。第一个匹配抛出对象类型的catch子句会处理该异常。如果catch子句未指定类型,则该子句可以处理任何类型的抛出对象:

dart
try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // 特定异常
  buyMoreLlamas();
} on Exception catch (e) {
  // 其他任何异常
  print('Unknown exception: $e');
} catch (e) {
  // 未指定类型,处理所有异常
  print('Something really unknown: $e');
}

如前面的代码所示,你可以使用oncatch或两者结合。需要指定异常类型时用on,异常处理程序需要异常对象时用catch

你可以为catch()指定一个或两个参数。第一个是抛出的异常,第二个是堆栈跟踪(StackTrace对象)。

dart
try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

若要部分处理异常,同时允许它继续传播,可以使用rethrow关键字。

dart
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子句执行后异常会继续传播:

dart
try {
  breedMoreLlamas();
} finally {
  // 始终清理,即使抛出异常
  cleanLlamaStalls();
}

finally子句会在任何匹配的catch子句之后执行:

dart
try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // 先处理异常
} finally {
  cleanLlamaStalls(); // 然后清理
}

如需了解更多,请查阅核心库的异常文档。

断言

在开发过程中,可以使用断言语句——assert(<condition>, <optionalMessage>);——在布尔条件为假时中断正常执行。

dart
// 确保变量不为null
assert(text != null);

// 确保值小于100
assert(number < 100);

// 确保这是https URL
assert(urlString.startsWith('https'));

若要为断言附加消息,可将字符串作为assert的第二个参数(可选添加尾随逗号):

dart
assert(
  urlString.startsWith('https'),
  'URL ($urlString) should start with "https".',
);

assert的第一个参数可以是任何解析为布尔值的表达式。如果表达式的值为true,断言成功,程序继续执行;如果为false,断言失败,抛出异常(AssertionError)。

断言何时生效?这取决于你使用的工具和框架:

  • Flutter在调试模式下启用断言。
  • 仅用于开发的工具(如webdev serve)通常默认启用断言。
  • 某些工具(如dart rundart compile js)支持通过命令行标志--enable-asserts启用断言。
  • 在生产代码中,断言会被忽略,assert的参数也不会被求值。