1. 揭开异常处理的神秘面纱

在Dart的世界里,异常就像不期而至的快递包裹——既可能装着重要信息,也可能是需要谨慎处理的危险品。想象一下这样的场景:用户正在使用你开发的天气APP,突然遇到网络闪断,如果没有妥善处理异常,用户可能会看到白屏或直接闪退。这就是为什么我们需要深入理解Dart异常处理机制的原因。

示例1:最简单的生存防护

void main() {
  try {
    // 可能导致异常的业务代码
    print(100 ~/ 0); // 触发整数除以零异常
  } catch (e) {
    // 异常捕获处理
    print('优雅处理异常:$e');
  } finally {
    // 必须执行的清理工作
    print('资源清理完成');
  }
}

(技术栈:Dart 3.0+)

2. 详解异常处理双雄

Dart将错误分为两大类:Exception和Error,就像医院分门诊和急诊一样。Exception通常是可预期的运行错误,如网络请求超时;而Error则对应着严重程序错误,比如内存溢出。

2.1 同步异常捕获战术

示例2:定制化异常处理

class PaymentException implements Exception {
  final String message;
  PaymentException(this.message);

  @override
  String toString() => '支付异常:$message';
}

void processPayment(double amount) {
  if (amount <= 0) {
    throw PaymentException('无效的支付金额:$amount');
  }
  // 正常支付逻辑...
}

void main() {
  try {
    processPayment(-100);
  } on PaymentException catch (e) {
    print('定制化异常处理:$e');
  } catch (e) {
    print('通用异常捕获:$e');
  }
}

2.2 异步战场生存指南

示例3:Future异常处理策略

Future<void> fetchUserData() async {
  await Future.delayed(Duration(seconds: 1));
  throw FormatException('数据解析错误');
}

void main() {
  fetchUserData().catchError((error) {
    print('捕获异步错误:${error.toString()}');
  }).whenComplete(() => print('请求流程结束'));
}

3. 高手进阶技巧

3.1 异常传播链解密

Dart的异常传播遵循"逐级上报"原则,就像公司的问题汇报机制。未捕获的异常会导致isolate终止,在Flutter中表现为应用崩溃。

示例4:嵌套异常处理

void processOrder() {
  try {
    verifyInventory();
  } catch (e) {
    print('库存校验失败:$e');
    throw OrderException('订单处理失败'); // 封装原始异常
  }
}

void main() {
  try {
    processOrder();
  } on OrderException catch (e) {
    print('捕获封装的异常:$e');
    print('原始错误堆栈:${e.stackTrace}');
  }
}

3.2 Zone防御工事构建

Zone就像给代码执行环境加装的安全气囊,特别适合全局异常捕获。

示例5:全局异常拦截系统

void main() {
  runZonedGuarded(() {
    Future.error('未处理的异步错误');
  }, (error, stackTrace) {
    print('全局捕获异常:$error');
    print('错误堆栈追踪:$stackTrace');
  });
}

4. 最佳实践路线图

4.1 异常类型的选择哲学

  • 业务异常继承Exception
  • 致命错误继承Error
  • 使用领域特定异常(如NetworkException)

4.2 错误处理的三层防御

  1. 边界防御层:入口参数校验

    void updateProfile(User user) {
      if (user == null) throw ArgumentError('用户对象不能为空');
      // ...后续逻辑
    }
    
  2. 战术处理层:精准捕获异常

    try {
      parseJSON(data);
    } on FormatException {
      // 特殊处理格式错误
    }
    
  3. 战略兜底层:全局异常处理

    void main() {
      FlutterError.onError = (details) {
        // 上报错误到监控平台
      };
    }
    

5. 实战场景演练场

5.1 网络请求综合处理

示例6:带重试机制的请求封装

Future<Response> fetchWithRetry(String url, {int retries = 3}) async {
  for (var i = 0; i < retries; i++) {
    try {
      return await http.get(Uri.parse(url));
    } on SocketException {
      print('网络连接失败,重试次数:${i + 1}');
      await Future.delayed(Duration(seconds: 1 << i));
    }
  }
  throw NetworkException('超过最大重试次数');
}

5.2 文件操作安全指南

示例7:带资源管理的文件操作

Future<void> writeConfigFile(String content) async {
  final file = File('config.yaml');
  try {
    await file.writeAsString(content);
  } on FileSystemException catch (e) {
    if (e.osError?.errorCode == 28) {
      throw StorageException('存储空间不足');
    }
    rethrow;
  } finally {
    await file.close();
  }
}

6. 技术选型深度比较

处理方式 适用场景 优点 缺点
try-catch 明确的代码边界 精确控制范围 嵌套层级较深时复杂
Zone全局捕获 未处理异常兜底 全面覆盖 无法定位具体位置
异步捕获链 Future/Stream流程控制 链式调用优雅 需要良好代码组织
isolate隔离 计算密集型任务 避免主流程崩溃 通信成本较高

7. 开发避坑指南针

  1. 不要忽视finally:即使有return也要执行
  2. 保持catch干净:避免在catch块中触发新异常
  3. 错误日志优化:携带上下文信息
    catch (e, stackTrace) {
      logger.error('用户支付失败', 
        error: e,
        stackTrace: stackTrace,
        extra: {'amount': 100}
      );
    }
    

8. 技术趋势瞭望台

Dart 3.0引入的增强型模式匹配为异常处理带来新可能:

try {
  // ...
} catch (e) {
  switch (e) {
    case NetworkTimeoutException():
      handleNetworkIssue();
    case PaymentDeclinedException():
      showPaymentError();
  }
}