通关 Dart 之路|异常处理之预见错误,优雅应对

学习 Dart 异常处理:预见错误,优雅应对

在程序运行过程中,异常是不可避免的。网络异常、文件读取错误、日期格式问题等,都可能引发程序中断。不仅需要处理异常以确保程序不中止,还能更轻松地排查问题。

1. 异常的触发

以下测试中,task1 方法将字符串转为数字,若传非数字,将产生转换异常,中断 task2 的执行。

void main(){
  task1('a');
  task2();
}

int task1(String num){
  return int.parse(num);
}

void task2(){
  print("Task2");
}

2. 异常的捕捉

使用 try...catch... 捕捉异常。catch 中的参数:

  • e 表示异常对象,如 FormatException
  • s_StackTrace,记录异常的栈信息
void main(){
  try{
    task1('a');
  } catch(e, s){
    print("${e.runtimeType}: ${e.toString()}"); 
    print("${s.runtimeType}: ${s.toString()}"); 
  }
  task2(); // Task2
}

异常被捕获,程序不中断,task2 仍执行。

3. 自定义异常与抛出

Exception 是异常的顶层抽象类,可构造运行时类型为 _Exception 的异常对象,传入信息。

void main() {
  try {
    getMean("about");
  } catch (e, s) {
    print("${e.runtimeType}: ${e.toString()}");
    print("${s.runtimeType}: ${s.toString()}");
  }
}

String getMean(String arg) {
  Map<String, String> dict = {"card": "卡片", "but": "但是"};
  String? result = dict[arg];
  if (result == null) {
    throw Exception("empty $arg mean in dict");
  }
  return result;
}

4. 分类异常处理

可拓展 Exception 类以自定义异常类型。使用 on/catch 捕获不同异常类型。

void main() {
  try {
    getMean("about");
  } on NoElementInDictException catch (e, s) {
    // 特定异常处理
  } catch (e, s) {
    // 其他异常处理
  }
}

5. finally 关键字

finally 用于 catch 之后,无论异常与否,都执行。避免多次重复写 finally 代码块。

void foo2(){
  try {
    getMean("about");
  } catch (e, s) {
    print("${e.runtimeType}: ${e.toString()}");
    print("${s.runtimeType}: ${s.toString()}");
  } finally{
    print("finally block called");
  }

异常处理是 Dart 编程的关键,确保程序鲁棒性和可维护性。遵循最佳实践,优雅应对异常,将让你的代码更具健壮性。

学习 Dart | 类与成员可见性

本文将深入探讨 Dart 中的类及其成员可见性,构建坚实的面向对象基础。

类的定义与实例化

Dart 使用 class 关键字定义类,通过 {} 定义类的作用域,包含成员变量和成员方法。

class $className$ {
  // 类体
}

1. 类的简单定义与实例化

Vec2 类为例,定义包含两个 double 变量的类,用构造方法初始化。

class Vec2 {
  double x;
  double y;

  Vec2(this.x, this.y);
}

通过构造方法实例化 Vec2 类,访问和修改成员变量:

void main() {
  Vec2 p0 = Vec2(4, 3);
  print("Vec2(${p0.x},${p0.y})"); // Vec2(4.0,3.0)
  p0.x = 15;
  print("Vec2(${p0.x},${p0.y})"); // Vec2(15.0,3.0)
}

2. 成员方法

除成员变量外,类还可以定义成员方法。例如,为 Vec2 提供 getInfo 方法获取打印信息:

class Vec2 {
  double x;
  double y;

  Vec2(this.x, this.y);

  String getInfo() => "Vec2($x,$y)";
}

调用成员方法简化代码:

void main() {
  Vec2 p0 = Vec2(4, 3);
  print(p0.getInfo()); // Vec2(4.0,3.0)
  p0.x = 15;
  print(p0.getInfo()); // Vec2(15.0,3.0)
}

3. get 与 set 关键字

getset 修饰成员方法,提供属性式访问。如 length 计算向量长度:

class Vec2 {
  // ...
  double get length => math.sqrt(x * x + y * y);
}

使用属性式访问 length

Vec2 p0 = Vec2(4, 3);
print(p0.length); // 5.0

4. 类的构造方法

构造方法是连接类与对象的桥梁,特点包括无返回值、可无方法体、可对成员进行赋值。

class Vec2 {
  double x;
  double y;

  Vec2(this.x, this.y);
}

使用构造方法实例化对象,支持命名参数:

Vec2 p0 = Vec2(4, 3);
Vec2 p1 = Vec2(argX: 4, argY: 3);

5. 命名构造

通过命名构造创建多种实例化方式,如 Vec2.polar 构造方法:

class Vec2 {
  Vec2.polar(double length, double rad)
      : x = length * math.cos(rad),
        y = length * math.sin(rad);
}

使用命名构造创建对象:

Vec2 p1 = Vec2.polar(10, math.pi / 4);

成员和类的可见性

使用 _ 前缀限制成员可见性,私有成员仅限同一文件访问。

class Vec2 {
  double x;
  double y;
  String? _name;

  Vec2(this.x, this.y);

  String getInfo() => "${name}Vec2($x,$y)";

  double get length => math.sqrt(x * x + y * y);

  String get name => _name ?? "";

  set name(String? value) {
    _name = value == null ? "" : value + ": ";
  }
}

限制私有成员可见性,保障封装与安全性。

静态成员与静态方法

静态成员由类直接访问,使用 static 关键字定义静态成员和静态方法:

class Person {
  String name;
  static String nation = "";

  Person(this.name);

  static void printNation() {
    print("Current nation is: $nation");
  }

  void say() {
    print("I am $name, from $nation");
  }
}

使用静态成员和静态方法,无需实例化对象:

Person.nation = "Tang Dynasty";
print(Person.nation); // Tang Dynasty
Person.printNation(); // Current nation is: Tang Dynasty

通过类直接访问静态成员,实现全局共享数据和方法。

结语

本文深入介绍了 Dart 类的定义与实例化、构造方法、成员方法、可见性和静态成员等基础概念。掌握这些核心概念将帮助你更好地构建健壮的面向对象程序,为进一步探索类与类间的关系打下坚实基础。

全部评论

相关推荐

伟大的烤冷面被普调:暨大✌🏻就是强
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务