Dart語言 4 異常和類

異常

Dart代碼可以拋出并捕獲異常。如果未捕獲異常,則會引發(fā)程序終止

與Java相比懦窘,Dart的所有異常都是未經(jīng)檢查的異常。方法不會聲明它們可能引發(fā)的異常稚配,并且您不需要捕獲任何異常畅涂。

Dart提供了Exception和Error類型,以及許多預(yù)定義的子類型道川。當(dāng)然午衰,您可以定義自己的異常。Dart可以拋出任何非null異常冒萄。
拋出異常
以下是拋出或引發(fā)異常的示例:

throw FormatException('這是一個異常');

你也可以拋出任意對象:

throw 'Out of llamas!';

注意:應(yīng)該盡可能的拋出錯誤或異常的類型臊岸。

因為拋出異常是一個表達(dá)式,所以可以在=>語句中以及允許表達(dá)式的任何其他地方拋出異常:

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

捕獲
捕獲異常會阻止異常傳遞(除非您重新拋出異常)尊流。捕獲異常使您有機(jī)會處理它:

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()指定一個或兩個參數(shù)忿晕。第一個是拋出的異常装诡,第二個是堆棧跟蹤(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關(guān)鍵字:

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
無論是否拋出異常鸦采,要確保某些代碼運(yùn)行,請使用finally子句咕幻。 如果沒有catch子句與異常匹配渔伯,則在finally子句運(yùn)行后傳遞異常:

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.
}


獲取對象的類型
要在運(yùn)行時獲取對象的類型,可以使用Object的runtimeType屬性肄程,該屬性返回Type對象锣吼。

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

以下是聲明實例變量的方法:

class Point {
  num x; //聲明實例變量x,最初為null蓝厌。
  數(shù)字; //聲明y玄叠,最初為null。
  num z = 0; //聲明z拓提,最初為0读恃。
}

所有未初始化的實例變量的值都為null

所有實例變量都生成一個隱式getter方法。非最終實例變量也會生成隱式setter方法寺惫。

構(gòu)造函數(shù) :

通過創(chuàng)建與其類同名的函數(shù)來聲明構(gòu)造函數(shù)(另外疹吃,可選地,如命名構(gòu)造函數(shù)中所述的附加標(biāo)識符)肌蜻。最常見的構(gòu)造函數(shù)形式,即生成構(gòu)造函數(shù)必尼,創(chuàng)建一個類的新實例:

class Point {
  num x蒋搜,y;

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

this關(guān)鍵字引用當(dāng)前實例判莉。

將構(gòu)造函數(shù)參數(shù)賦值給實例變量的模式是如此常見豆挽,Dart具有語法糖,使其變得簡單:

class Point {
  num x券盅,y;

  //用于設(shè)置x和y的語法糖
  //在構(gòu)造函數(shù)體運(yùn)行之前
  Point(this.x帮哈,this.y);
}

默認(rèn)構(gòu)造函數(shù)
如果您未聲明構(gòu)造函數(shù),則會為您提供默認(rèn)構(gòu)造函數(shù)锰镀。默認(rèn)構(gòu)造函數(shù)沒有參數(shù)娘侍,并在超類中調(diào)用無參數(shù)構(gòu)造函數(shù)。

構(gòu)造函數(shù)不是繼承的
子類不從其超類繼承構(gòu)造函數(shù)泳炉。聲明沒有構(gòu)造函數(shù)的子類只有默認(rèn)(無參數(shù)憾筏,無名稱)構(gòu)造函數(shù)。

命名構(gòu)造函數(shù)
使用命名構(gòu)造函數(shù)為類實現(xiàn)多個構(gòu)造函數(shù)或提供額外的清晰度:

class Point {
  num x, y;

  Point(this.x, this.y);

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

請記住花鹅,構(gòu)造函數(shù)是不繼承的氧腰,這意味著超類的命名構(gòu)造函數(shù)不會被子類繼承。如果希望使用超類中定義的命名構(gòu)造函數(shù)創(chuàng)建子類刨肃,則必須在子類中實現(xiàn)該構(gòu)造函數(shù)古拴。

調(diào)用非默認(rèn)的超類構(gòu)造函數(shù)
默認(rèn)情況下,子類中的構(gòu)造函數(shù)調(diào)用超類的未命名的無參數(shù)構(gòu)造函數(shù)真友。超類的構(gòu)造函數(shù)在構(gòu)造函數(shù)體的開頭被調(diào)用黄痪。如果還使用初始化列表,則在調(diào)用超類之前執(zhí)行盔然÷Γ總之,執(zhí)行順序如下:

  • 初始化列表
  • 超類的無參數(shù)構(gòu)造函數(shù)
  • 主類的無參數(shù)構(gòu)造函數(shù)

如果超類沒有未命名的無參數(shù)構(gòu)造函數(shù)轻纪,則必須手動調(diào)用超類中的一個構(gòu)造函數(shù)油额。在冒號(:)之后指定超類構(gòu)造函數(shù),就在構(gòu)造函數(shù)體(如果有)之前刻帚。

常量構(gòu)造函數(shù)
如果您的類生成永遠(yuǎn)不會更改的對象潦嘶,則可以使這些對象成為編譯時常量。為此崇众,請定義const構(gòu)造函數(shù)并確保所有實例變量都是final:

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

  final num x, y;

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

工廠建設(shè)者
在實現(xiàn)并不總是創(chuàng)建其類的新實例的構(gòu)造函數(shù)時掂僵,請使用factory關(guān)鍵字航厚。例如,工廠構(gòu)造函數(shù)可能從緩存中返回實例锰蓬,或者它可能返回子類型的實例幔睬。

以下示例演示了從緩存中返回對象的工廠構(gòu)造函數(shù):

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);
  }
}

注意:工廠構(gòu)造函數(shù)無權(quán)訪問this

像調(diào)用任何其他構(gòu)造函數(shù)一樣調(diào)用工廠構(gòu)造函數(shù):

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

getters and setters
gettersetter是提供對象屬性的讀寫訪問權(quán)限的特殊方法芹扭÷槎ィ回想一下,每個實例變量都有一個隱式getter舱卡,如果合適的話還有一個setter辅肾。您可以使用getset關(guān)鍵字通過實現(xiàn)gettersetter來創(chuàng)建其他屬性:

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方法可以是抽象的轮锥,定義一個接口矫钓,但將其實現(xiàn)留給其他類。 抽象方法只能存在于抽象類中舍杜。
要使方法成為抽象新娜,請使用分號(;)而不是方法體:


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()));
}

這是一個指定類實現(xiàn)多個接口的示例:

class Point implements Comparable, Location {...}

繼承extending
使用extends創(chuàng)建子類,使用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() {...}
}

重載運(yùn)算符

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));
}

注意:如果覆蓋==,則還應(yīng)該覆蓋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是一種在多個類層次結(jié)構(gòu)中重用類代碼的方法。
要使用mixin颜矿,請使用with關(guān)鍵字后跟一個或多個mixin名稱寄猩。以下示例顯示了兩個使用mixins的類:

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

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

要實現(xiàn)mixin,請創(chuàng)建一個擴(kuò)展Object的類骑疆,并且不聲明構(gòu)造函數(shù)田篇。除非您希望mixin可用作常規(guī)類,否則請使用mixin關(guān)鍵字而不是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可以調(diào)用它沒有定義的方法 , 使用on來指定所需的超類:

mixin MusicalPerformer on Musician {
  // ···
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市诈火,隨后出現(xiàn)的幾起案子兽赁,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刀崖,死亡現(xiàn)場離奇詭異惊科,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)亮钦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門馆截,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜂莉,你說我怎么就攤上這事蜡娶。” “怎么了巡语?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵翎蹈,是天一觀的道長淮菠。 經(jīng)常有香客問我男公,道長,這世上最難降的妖魔是什么合陵? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任枢赔,我火速辦了婚禮,結(jié)果婚禮上拥知,老公的妹妹穿的比我還像新娘踏拜。我一直安慰自己,他們只是感情好低剔,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布速梗。 她就那樣靜靜地躺著,像睡著了一般襟齿。 火紅的嫁衣襯著肌膚如雪姻锁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天猜欺,我揣著相機(jī)與錄音位隶,去河邊找鬼。 笑死开皿,一個胖子當(dāng)著我的面吹牛涧黄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赋荆,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼笋妥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了窄潭?” 一聲冷哼從身側(cè)響起挽鞠,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后信认,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體材义,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年嫁赏,在試婚紗的時候發(fā)現(xiàn)自己被綠了其掂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡潦蝇,死狀恐怖款熬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情攘乒,我是刑警寧澤贤牛,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站则酝,受9級特大地震影響殉簸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沽讹,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一般卑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爽雄,春花似錦蝠检、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乘盖,卻和暖如春焰檩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背侧漓。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工锅尘, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人布蔗。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓藤违,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纵揍。 傳聞我的和親對象是個殘疾皇子顿乒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容