Dart 之异常处理

前言

在代码的世界里,异常如同旅途中的意外天气,无论准备如何详细,也无法完全避免台风、地震等问题。而异常处理机制,正是让程序从"脆弱易崩"走向"健壮可靠"的关键。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中支持自定义异常的类型,通过继承ExceptionError创建自定义异常。

示例:

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关键字处理异常),然后介绍了自定义异常与异常传播,最后对异常处理的使用进行了建议。

相关推荐
故事与他6453 小时前
Thinkphp(TP)框架漏洞攻略
android·服务器·网络·中间件·tomcat
每次的天空5 小时前
项目总结:GetX + Kotlin 协程实现跨端音乐播放实时同步
android·开发语言·kotlin
m0_748233177 小时前
SQL之delete、truncate和drop区别
android·数据库·sql
书弋江山7 小时前
flutter 自定义控件RenderObjectWidget使用
前端·javascript·flutter
CYRUS_STUDIO9 小时前
OLLVM 增加 C&C++ 字符串加密功能
android·c++·安全
帅次10 小时前
Flutter 输入组件 Radio 详解
android·flutter·ios·kotlin·android studio
&有梦想的咸鱼&11 小时前
Android Compose 框架的状态与 ViewModel 的协同(collectAsState)深入剖析(二十一)
android
开开心心就好11 小时前
高效PDF翻译解决方案:多引擎支持+格式零丢失
android·java·网络协议·tcp/ip·macos·智能手机·pdf
路上阡陌12 小时前
docker 安装部署 canal
android·adb·docker
&有梦想的咸鱼&13 小时前
入剖析 Android Compose 框架的关键帧动画(keyframes、Animatable)(二十三)
android