Dart语言 4 异常和类

异常

Dart代码可以抛出并捕获异常。如果未捕获异常,则会引发程序终止

与Java相比,Dart的所有异常都是未经检查的异常。方法不会声明它们可能引发的异常,并且您不需要捕获任何异常。

Dart提供了Exception和Error类型,以及许多预定义的子类型。当然,您可以定义自己的异常。Dart可以抛出任何非null异常。
抛出异常
以下是抛出或引发异常的示例:

throw FormatException('这是一个异常');

你也可以抛出任意对象:

throw 'Out of llamas!';

注意:应该尽可能的抛出错误或异常的类型。

因为抛出异常是一个表达式,所以可以在=>语句中以及允许表达式的任何其他地方抛出异常:

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

捕获
捕获异常会阻止异常传递(除非您重新抛出异常)。捕获异常使您有机会处理它:

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

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

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}

如前面的代码所示,您可以使用on或catch或两者。需要指定异常类型时使用。在异常处理程序需要异常对象时使用catch。
您可以为catch()指定一个或两个参数。第一个是抛出的异常,第二个是堆栈跟踪(StackTrace对象):

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

要部分处理异常,同时允许它传播,请使用rethrow关键字:

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // Runtime error
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // Allow callers to see the exception.
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}

Finally
无论是否抛出异常,要确保某些代码运行,请使用finally子句。 如果没有catch子句与异常匹配,则在finally子句运行后传递异常:

try {
  breedMoreLlamas();
} finally {
  // Always clean up, even if an exception is thrown.
  cleanLlamaStalls();
}
The finally clause runs after any matching catch clauses:

try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // Handle the exception first.
} finally {
  cleanLlamaStalls(); // Then clean up.
}


获取对象的类型
要在运行时获取对象的类型,可以使用Object的runtimeType属性,该属性返回Type对象。

print('a type is ${a.runtimeType}');

以下是声明实例变量的方法:

class Point {
  num x; //声明实例变量x,最初为null。
  数字; //声明y,最初为null。
  num z = 0; //声明z,最初为0。
}

所有未初始化的实例变量的值都为null

所有实例变量都生成一个隐式getter方法。非最终实例变量也会生成隐式setter方法。

构造函数 :

通过创建与其类同名的函数来声明构造函数(另外,可选地,如命名构造函数中所述的附加标识符)。最常见的构造函数形式,即生成构造函数,创建一个类的新实例:

class Point {
  num x,y;

  Point(num x,num y){
    this.x = x;
    this.y = y;
  }
}

this关键字引用当前实例。

将构造函数参数赋值给实例变量的模式是如此常见,Dart具有语法糖,使其变得简单:

class Point {
  num x,y;

  //用于设置x和y的语法糖
  //在构造函数体运行之前
  Point(this.x,this.y);
}

默认构造函数
如果您未声明构造函数,则会为您提供默认构造函数。默认构造函数没有参数,并在超类中调用无参数构造函数。

构造函数不是继承的
子类不从其超类继承构造函数。声明没有构造函数的子类只有默认(无参数,无名称)构造函数。

命名构造函数
使用命名构造函数为类实现多个构造函数或提供额外的清晰度:

class Point {
  num x, y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}

请记住,构造函数是不继承的,这意味着超类的命名构造函数不会被子类继承。如果希望使用超类中定义的命名构造函数创建子类,则必须在子类中实现该构造函数。

调用非默认的超类构造函数
默认情况下,子类中的构造函数调用超类的未命名的无参数构造函数。超类的构造函数在构造函数体的开头被调用。如果还使用初始化列表,则在调用超类之前执行。总之,执行顺序如下:

  • 初始化列表
  • 超类的无参数构造函数
  • 主类的无参数构造函数

如果超类没有未命名的无参数构造函数,则必须手动调用超类中的一个构造函数。在冒号(:)之后指定超类构造函数,就在构造函数体(如果有)之前。

常量构造函数
如果您的类生成永远不会更改的对象,则可以使这些对象成为编译时常量。为此,请定义const构造函数并确保所有实例变量都是final:

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}

工厂建设者
在实现并不总是创建其类的新实例的构造函数时,请使用factory关键字。例如,工厂构造函数可能从缓存中返回实例,或者它可能返回子类型的实例。

以下示例演示了从缓存中返回对象的工厂构造函数:

class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

注意:工厂构造函数无权访问this

像调用任何其他构造函数一样调用工厂构造函数:

var logger = Logger('UI');
logger.log('Button clicked');

getters and setters
gettersetter是提供对象属性的读写访问权限的特殊方法。回想一下,每个实例变量都有一个隐式getter,如果合适的话还有一个setter。您可以使用getset关键字通过实现gettersetter来创建其他属性:

class Rectangle {
  num left, top, width, height;

  Rectangle(this.left, this.top, this.width, this.height);

  // Define two calculated properties: right and bottom.
  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

抽象方法
实例、getter和setter方法可以是抽象的,定义一个接口,但将其实现留给其他类。 抽象方法只能存在于抽象类中。
要使方法成为抽象,请使用分号(;)而不是方法体:


abstract class Doer {
  // Define instance variables and methods...

  void doSomething(); // Define an abstract method.
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // Provide an implementation, so the method is not abstract here...
  }
}

抽象类

// A person. The implicit interface contains greet().
class Person {
  // In the interface, but visible only in this library.
  final _name;

  // Not in the interface, since this is a constructor.
  Person(this._name);

  // In the interface.
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.
class Impostor implements Person {
  get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

这是一个指定类实现多个接口的示例:

class Point implements Comparable, Location {...}

继承extending
使用extends创建子类,使用super来引用超类:

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
}

子类可以覆盖实例方法,gettersetter。 您可以使用@override注释来指示您有意覆盖成员:

class SmartTelevision extends Television {
  @override
  void turnOn() {...}
}

重载运算符

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

  // Operator == and hashCode not shown. For details, see note below.
  // ···
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}

注意:如果覆盖==,则还应该覆盖ObjecthashCode getter方法。

枚举类型

enum Color { red, green, blue }

枚举中的每个值都有一个索引getter,它返回枚举声明中值的从零开始的位置。例如,第一个值具有索引0,第二个值具有索引1:

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

mixins
Mixins是一种在多个类层次结构中重用类代码的方法。
要使用mixin,请使用with关键字后跟一个或多个mixin名称。以下示例显示了两个使用mixins的类:

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

要实现mixin,请创建一个扩展Object的类,并且不声明构造函数。除非您希望mixin可用作常规类,否则请使用mixin关键字而不是class

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

要指定只有某些类型可以使用mixin - 例如,你的mixin可以调用它没有定义的方法 , 使用on来指定所需的超类:

mixin MusicalPerformer on Musician {
  // ···
}

猜你喜欢

转载自blog.csdn.net/weixin_33890526/article/details/87334502