7.異常泣矛、斷言和日志

1.概述

  • Java提供異常處理機(jī)制來(lái)處理異常
  • 斷言:在測(cè)試中旦棉,不需要寫測(cè)試代碼齿风,測(cè)試完將代碼刪除。我們使用斷言來(lái)有選擇性的進(jìn)行測(cè)試
  • 日志:記錄下出現(xiàn)的問(wèn)題绑洛,已備日后分析

2.處理錯(cuò)誤

2.1 異常分類

exception.png
  • Error:描述了運(yùn)行時(shí)系統(tǒng)的我內(nèi)部錯(cuò)誤等救斑。一般除了通知用戶,并盡力使程序安全終止外真屯,無(wú)能為力
  • Exception:根據(jù)unchecked分為unchecked Exception和checked Exception
    • RuntimeExcetion:unchecked Exception脸候。
      • NullPointerException
      • ClassCastException
      • ArrayIndexOutOfBoundsException
    • IOException:checked Exception
      • 如試圖打開(kāi)一個(gè)不存在的文件
      • 試圖在文件尾部后面讀取數(shù)據(jù)
  • 編譯器會(huì)檢查是否為所有的checked Exception提供了異常處理器。也就是編譯期間绑蔫,編譯器會(huì)檢查你有沒(méi)有對(duì)IOException進(jìn)行異常處理运沦,但是不會(huì)關(guān)心你否處理了數(shù)組越界異常

2.2 聲明checked異常

  • 每個(gè)包含的checked異常的方法都需要通過(guò)throws聲明具體可能會(huì)拋出什么異常,包含多個(gè)checked Exception則需要聲明多個(gè)配深。
  • 什么時(shí)候需要拋出異常携添?
    • 調(diào)用會(huì)拋出checked Exception的方法時(shí)
    • 方法本身利用throw,拋出異常時(shí)
    • 程序出現(xiàn)運(yùn)行時(shí)異常
    • 系統(tǒng)和內(nèi)部錯(cuò)誤
  • 什么時(shí)候需要聲明異常呢篓叶?
    • 上述前兩種情況
    • 不需要聲明系統(tǒng)錯(cuò)誤以及運(yùn)行時(shí)的unchecked Exception烈掠,也就是RuntimeException羞秤。我們應(yīng)該盡力去修正這些RuntimeException。
    • 總之左敌,一個(gè)方法必須聲明所有可能拋出的受查異常瘾蛋,而非受查異常要么不可控制(Error),要么就應(yīng)該避免發(fā)生(RuntimeException)
  • 異辰孟蓿可以被拋出哺哼,也可以被捕獲,具體采用什么策略要看具體情況

3.捕獲異常

3.1 捕獲異常

  • 捕獲異常叼风,必須設(shè)置try/catch語(yǔ)句塊
  • 如果調(diào)用了一個(gè)拋出受查異常的方法取董,就必須對(duì)它進(jìn)行處理,或者繼續(xù)傳遞咬扇。
  • 通常甲葬,應(yīng)該捕獲那些知道如何處理的異常,而將那些不知道怎樣處理的異常繼續(xù)進(jìn)行傳遞
  • 如果想傳遞一個(gè)異常懈贺,就必須在方法的首部添加一個(gè)throws說(shuō)明符经窖,以便告知調(diào)用者這個(gè)方法可能會(huì)拋出異常
  • 注意:如果編寫一個(gè)覆蓋超類的方法,而這個(gè)方法又沒(méi)有拋出異常(如JComponent中的paintComponent)梭灿,那么這個(gè)方法就必須捕獲方法代碼中出現(xiàn)的每一個(gè)受查異常画侣。不允許在子類的throws說(shuō)明符中出現(xiàn)超過(guò)超類方法所列出的異常類范圍

3. 2 捕獲多個(gè)異常

  • 在一個(gè)try語(yǔ)句塊中,可以捕獲多個(gè)異常堡妒,并對(duì)不同類型的異常做出不同的處理

3.3 再次拋出異常和異常鏈

  • catch子句中可以拋出異常配乱,這樣做的目的是改變異常的類型,如:
      try
      {
      }
      catch(SQLException e)
      {
        throw new ServletException();
      }
    
  • 另一種更好的辦法:將原始異常作為新異常的原因
      try
      {
      }
      catch(SQLException e)
      {
        Throwable se = new ServletException();
        se.initCause(e);
        throw se;
      }
    
    獲取到異常后皮迟,使用下面這條語(yǔ)句重新得到異常:se.getCause()
  • 如果在一個(gè)方法中發(fā)生了一個(gè)受查異常搬泥,而不允許拋出它,那么包裝技術(shù)就十分有用伏尼。我們可以捕獲這個(gè)受查異常忿檩,并將它包裝成一個(gè)運(yùn)行時(shí)異常

3.4 finally子句

  • 當(dāng)finally子句包含return語(yǔ)句時(shí),將會(huì)出現(xiàn)一種意想不到的結(jié)果爆阶。假設(shè)利用return語(yǔ)句從try語(yǔ)句塊中退出燥透。在方法返回前,finally子句的內(nèi)容將被執(zhí)行辨图。如果finally子句中也有一個(gè)return語(yǔ)句班套,這個(gè)返回值將會(huì)覆蓋原始的返回值。請(qǐng)看一個(gè)復(fù)雜的例子:
      public static int f(int n)
      {
        try
        {
          int r=2;
          return r;
        }
        finally
        {
          if (r=2) return 0;
        }
      }
    

3.5 帶資源的try語(yǔ)句

  • 帶資源的try語(yǔ)句:try塊退出時(shí)或存在一個(gè)異常時(shí)故河,會(huì)自動(dòng)調(diào)用res.close()
  • 如果try塊拋出一個(gè)異常吱韭,而且close方法也拋出一個(gè)異常,這就會(huì)帶來(lái)一個(gè)難題鱼的。帶資源的try語(yǔ)句可以很好地處理這種情況理盆。原來(lái)的異常會(huì)重新拋出瞻讽,而close方法拋出的異常會(huì)“被抑制”。這些異常將自動(dòng)捕獲熏挎,并由addSuppressed方法增加到原來(lái)的異常。如果對(duì)這些異常感興趣晌砾,可以調(diào)用getSuppressed方法坎拐,它會(huì)得到從close方法拋出并被抑制的異常列表。

3.6 分析堆棧軌跡元素

  • 堆棧軌跡(stack trace)是一個(gè)方法調(diào)用過(guò)程的列表养匈,它包含了程序執(zhí)行過(guò)程中方法調(diào)用的特定位置
  • 可以調(diào)用Throwable類的printStackTrace方法訪問(wèn)堆棧軌跡的文本描述信息
  • 一種更靈活的方法是使用getStackTrace方法哼勇,它會(huì)得到StackTraceElement對(duì)象的一個(gè)數(shù)組,可以在你的程序中分析這個(gè)對(duì)象數(shù)組
  • StackTraceElement類含有能夠獲得文件名和當(dāng)前執(zhí)行的代碼行號(hào)的方法呕乎,同時(shí)积担,還含有能夠獲得類名和方法名的方法

4.使用異常機(jī)制的技巧

  1. 異常處理不能代替簡(jiǎn)單的測(cè)試
    對(duì)比下面兩段代碼:
if(!s.empty)s.pop;
與
try
{
}
catch(EmptyStackException e)

捕獲異常花費(fèi)的執(zhí)行時(shí)間相比于前者是巨大的猬仁,因此:只在異常情況下使用異常機(jī)制

  1. 利用異常層次結(jié)構(gòu)
    不要只拋出RuntimeException異常。應(yīng)該尋找更加適當(dāng)?shù)淖宇惢騽?chuàng)建自己的異常類
    不要只捕獲Thowable異常,否則朽们,會(huì)使程序代碼更難讀奶镶、更難維護(hù)
  2. 不要壓制異常
  3. 在檢測(cè)錯(cuò)誤時(shí),“苛刻”要比放任更好
    例如诈闺,當(dāng)椏是欤空時(shí),Stack.pop是返回一個(gè)null雅镊,還是拋出一個(gè)異常襟雷?我們認(rèn)為:在出錯(cuò)的地方拋出一個(gè)EmptyStackException異常要比在后面拋出一個(gè)NullPointerException異常更好
  4. 不要羞于傳遞異常

4-5總結(jié)起來(lái)就是”早拋出,晚捕獲“

5.斷言

5.1 斷言是什么

double y = Math.sqrt(x)

假設(shè)我們編寫了以上代碼仁烹,此時(shí)我們需要檢測(cè)x是否大于0耸弄,我們可以這樣做:

if (x<0) throw new IllegalArgumentException();

但是這樣這段代碼會(huì)一直保留在程序中,即使測(cè)試完畢也不會(huì)自動(dòng)刪除晃危。如果程序中含有大量這種檢查叙赚,程序運(yùn)行起來(lái)會(huì)相當(dāng)慢

  • 斷言機(jī)制允許在測(cè)試期間向代碼中插入一些檢查語(yǔ)句。當(dāng)代碼發(fā)布時(shí)僚饭,這些插入的檢測(cè)語(yǔ)句將會(huì)被自動(dòng)移走震叮。

5.2 斷言的使用

assert 條件;
或
assert 條件:表達(dá)式鳍鸵;

這兩種形式都會(huì)對(duì)條件進(jìn)行檢測(cè)苇瓣,如果結(jié)果為false,則拋出一個(gè)AssertionError異常偿乖。在第二種形式中击罪,表達(dá)式將被傳入AssertionError的構(gòu)造器哲嘲,并轉(zhuǎn)換成一個(gè)消息字符串

5.3 什么時(shí)候使用斷言

java中給出了3種處理系統(tǒng)異常的機(jī)制:

  1. 拋出一個(gè)異常
  2. 日志
  3. 斷言
  • 什么時(shí)候使用斷言
    錯(cuò)誤1. 斷言失敗是致命的、不可恢復(fù)的錯(cuò)誤
  1. 斷言檢查只用于開(kāi)發(fā)和測(cè)階段

因此不應(yīng)該使用斷言向程序的其他部分通告發(fā)生了可恢復(fù)性的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末媳禁,一起剝皮案震驚了整個(gè)濱河市眠副,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竣稽,老刑警劉巖囱怕,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異毫别,居然都是意外死亡娃弓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門岛宦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)台丛,“玉大人,你說(shuō)我怎么就攤上這事砾肺⊥烀梗” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵债沮,是天一觀的道長(zhǎng)炼吴。 經(jīng)常有香客問(wèn)我,道長(zhǎng)疫衩,這世上最難降的妖魔是什么硅蹦? 我笑而不...
    開(kāi)封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮闷煤,結(jié)果婚禮上童芹,老公的妹妹穿的比我還像新娘。我一直安慰自己鲤拿,他們只是感情好假褪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著近顷,像睡著了一般生音。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窒升,一...
    開(kāi)封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天缀遍,我揣著相機(jī)與錄音,去河邊找鬼饱须。 笑死域醇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播譬挚,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼锅铅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了减宣?” 一聲冷哼從身側(cè)響起盐须,我...
    開(kāi)封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漆腌,沒(méi)想到半個(gè)月后丰歌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屉凯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了眼溶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悠砚。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖堂飞,靈堂內(nèi)的尸體忽然破棺而出灌旧,到底是詐尸還是另有隱情,我是刑警寧澤绰筛,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布枢泰,位于F島的核電站,受9級(jí)特大地震影響铝噩,放射性物質(zhì)發(fā)生泄漏衡蚂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一骏庸、第九天 我趴在偏房一處隱蔽的房頂上張望毛甲。 院中可真熱鬧,春花似錦具被、人聲如沸玻募。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)七咧。三九已至,卻和暖如春叮叹,著一層夾襖步出監(jiān)牢的瞬間艾栋,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工衬横, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留裹粤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像遥诉,于是被迫代替她去往敵國(guó)和親拇泣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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