异常处理
Dart代码可以抛出(throw
)和捕获(catch
)异常(Exception
)。异常代表了程序的某种错误,也就是一些意想不到的事情。引发异常的代码分支及其上下文,即测试中的负向路径。
Dart的函数或方法不会声明它将抛出哪些异常; Dart也不强制要求捕获异常。如果异常发生了却不被处理,抛出异常的 isolate 将被挂起,且通常会被终止。第7章将详细讨论 isolate,这里将其视为一种内存独立的线程(如 main
函数所在的 main isolate)即可。
抛出异常 (trhow
)
Dart程序可以抛出(trhow
)什么?答案是除了null
外的任何东西。
// ch0208_1.dart
void main() {
throw 'something bad happened';
// Unhandled exception:
// something bad happened
}
此例使用throw
关键字,抛出了一个字符串。
Exception
和 Error
Dart提供了 Exception
和 Error
类及相关子类(第4章将介绍类),官方建议我们在产品代码中抛出 Exception
或 Error
的实现类。例如下面这些类实现了Exception
:
AnalysisException
DeferredLoadException
FileSystemException
FormatException
IOException
IsolateSpawnException
PathException
RemoteException
TimeoutException
我们也可以创建自己的异常类,并实现(implements
) Exception
或 Error
。
// ch0208_2.dart
void main() {
throw FooException();
}
class FooException implements Exception {}
Exception
与 Error
的区别:
-
Exception
旨在向外传递一个失败信息(例如超时异常TimeoutException
),以便通过编程的方式解决;它应该包含有用的信息,且希望被捕获。 -
Error
代表了程序员引起的错误(例如断言错误AssertionError
), 它理应被避免,且通常暗示了一个bug,我们不应捕获它。
捕获异常
捕获指定类型的异常
使用 try...on...catch
语法捕获异常。将可能抛出异常的代码放在try{}
代码块中,然后使用on
关键字捕获特定类型的异常。
// ch0208_3.dart
import 'dart:io';
void main() {
var str = 'dart';
try {
int.parse(str);
} on FormatException {
stderr.writeln('FormatException: Cannot parse "$str" as an integer.');
}
}
此例试图将字符串"dart"
转换为一个整数,引发了 FormatException
,随后被捕获。
捕获异常信息
使用catch
关键字捕获异常信息(即异常类型的一个实例)。
// ch0208_4.dart
void main() {
try {
int.parse('dart');
} on FormatException catch (ex) {
print(ex.message); // Output: Invalid radix-10 number
}
}
catch()
还有另一个可选参数,表示异常堆栈。
// ch0208_5.dart
void main() {
try {
int.parse('dart');
} on FormatException catch (e, s) {
print(e);
print(s);
}
}
重新抛出异常
使用 rethrow
关键字重新抛出异常,且保留原来的堆栈信息。
// ch0208_6.dart
void main() {
try {
parseInt('dart');
} catch (_, s) {// 2
print(s); // 2a
}
}
int parseInt(String str) {
try {
return int.parse(str);
} on FormatException catch (_, s) {
print(s); // 1a
rethrow; // 1
}
}
- 使用
rethow
关键字将捕获到的FormatException
再次抛出; - 这里仅用了
catch
(没有使用on
指定异常类型),表示捕获所有类型的异常。
捕获多种类型的异常
使用多个catch
子句来分别处理不同类型的异常。
//ch0206_7.dart
void main() {
print(safeDivide('8', '2'));
print(safeDivide('8', '0'));
print(safeDivide('hello', 'dart'));
}
(String? err, int) safeDivide(String a, String b) {
try {
return (null, int.parse(a) ~/ int.parse(b));
} on FormatException catch (e) {
return ('FormatException: ${e.source}', 0);
} on UnsupportedError catch (e) { // IntegerDivisionByZeroException
return ('UnsupportedError: ${e.message}', 0);
} on Exception catch (e) {
return ('unknown exception: $e', 0);
}
}
finally
无论try
代码块内是否发生了异常, finally
子句都将被执行。finally
子句通常用来关闭资源(如打开的系统文件)。
// ch0208_8.dart
void main() {
try {
print(2 ~/ 0);
} on UnsupportedError {
print('oops');
} finally {
print('done');
}
// Output:
// oops
// done
}