原文出處:http://dev2dev.bea.com/pub/a/2006/11/effective-exceptions.html

摘要

  Java開發(fā)人員做出的有關(guān)架構(gòu)的最重要的決定之一便是如何使用Java異常模型。Java異常處理成為社區(qū)中討論最多的話題之一。一些人認為 Java語言中的已檢查異常(Checked Exceptions)是一次失敗的嘗試。本文認為錯誤并不在于Java模型本身,而在于Java庫設(shè)計人員沒有認識到方法失敗的兩個基本原因。本文提倡 思考異常情況的本質(zhì),并描述了有助于用戶設(shè)計的設(shè)計模式。最后,本文討論了異常處理在面向方面編程(Aspect Oriented Programming)模型中作為橫切關(guān)注點(crosscutting concern)的情況。如果使用得當,Java異常將對程序開發(fā)人員大有裨益。本文將幫助讀者正確使用Java異常。

為什么異常非常重要

  Java應(yīng)用程序中的異常處理可以告訴用戶構(gòu)建應(yīng)用程序的架構(gòu)強度。架構(gòu)是指在應(yīng)用程序的各個層面上所做出的并始終遵守的決策。其中最重要的決 策之一便是應(yīng)用程序中類、子系統(tǒng)或?qū)又g進行互相通信的方式。方法通過Java異常可以為操作傳遞另一種結(jié)果,因此應(yīng)用程序架構(gòu)特別值得我們?nèi)リP(guān)注。

   判斷Java架構(gòu)師技能的高低和開發(fā)團隊是否訓(xùn)練有素,其中比較好的方法是查看應(yīng)用程序中的異常處理代碼。首先需要觀察的是有多少代碼專門用于捕捉異 常、記錄異常、確定發(fā)生的事件和異常轉(zhuǎn)化。簡潔、緊湊和有條理的異常處理表明團隊有使用Java異常的一致方法。當異常處理代碼的數(shù)量將要超過其他方面的 代碼時,可以斷定團隊成員之間的溝通已經(jīng)打破(或者這種溝通從一開始就不存在),每個人都用自己的方法來處理異常。

  臨時異常處理的結(jié)果 非常具有預(yù)見性。如果問團隊成員為什么在代碼的某個特定點丟棄、捕捉、或忽略某個異常,回答通常是:“除此之外,我不知道怎么做。”如果問他們在編寫代碼 的異常實際發(fā)生時會產(chǎn)生什么情況,他們通常會皺眉,回答類似于:“我不知道。我們從來沒有測試過。”

  要判斷Java組件是否有效地利用 了Java異常,可以查看其客戶端的代碼。如果客戶端代碼中包含大量計算操作失敗時間、原因和處理方法的邏輯,原因幾乎都是由于組件的錯誤報告設(shè)計。有缺 陷的報告會在客戶端產(chǎn)生大量的“記錄和遺留”(log and forget)代碼,而沒有任何用途。最糟糕的是扭曲的邏輯路徑、互相嵌套的try/catch/finally程序塊,以及其他導(dǎo)致脆弱和無法管理的應(yīng) 用程序的混亂。

  事后處理異常(或者根本不處理)是造成軟件項目混亂和延遲的主要原因。異常處理關(guān)系到軟件設(shè)計的各個方面。為異常建立架構(gòu)約定應(yīng)該是項目中首先要做出的決定之一。合理使用Java異常模型將對保持應(yīng)用程序的簡潔性、可維護性和正確性大有幫助。

挑戰(zhàn)異常準則

  如何正確使用Java異常模型已經(jīng)成為大量討論的主題。Java并不是支持異常語義的第一種語言;但是,通過Java編譯器可強制使用規(guī)則來控 制如何聲明和處理特定的異常。許多人認為編譯時異常檢查對精確軟件設(shè)計有幫助,它與其他語言特征能夠很好地協(xié)調(diào)起來。圖1表明了Java異常的層次結(jié)構(gòu)。

   通常,Java編譯器會根據(jù)java.lang.Throwable強制方法拋出異常,包括其聲明中“throw”子句的異常。同樣,編譯器會驗證方法 的客戶端是捕獲聲明異常類型還是指定自己拋出異常類型。這些簡單的規(guī)則對于全世界的Java開發(fā)人員產(chǎn)生了深遠的影響。

  編譯器針對 Throwable繼承樹的兩個分支放寬了異常檢查行為。java.lang.Error和java.lang.RuntimeException的子類 免于編譯時檢查。在兩者中,軟件設(shè)計人員通常對運行時異常更感興趣。通常使用術(shù)語“未檢查異常”(unchecked exception)來區(qū)分其他的所有“已檢查異常”(checked exception)

圖 1 Java異常層次結(jié)構(gòu)

我認為已檢查異常會受到那些重視Java語言中強類型的人的歡迎。畢竟,由編譯器對數(shù)據(jù)類型產(chǎn)生的約束會鼓勵嚴格編碼和精確思維。編譯時類型檢查有 助于防止在運行時產(chǎn)生難以應(yīng)付的意外事件。編譯時異常檢查將起到相同的效果,提醒開發(fā)人員注意的是,方法會有潛在的其他結(jié)果需要進行處理。

   在早期,推薦無論何處都盡量使用已檢查異常,以便充分借助編譯器生產(chǎn)出無差錯軟件。Java API庫的設(shè)計人員顯然贊成已檢查異常準則,并廣泛使用這些異常來模仿在庫方法中發(fā)生的任何意外事件。在J2SE 5.1 API規(guī)范中,已檢查異常類型仍然比未檢查異常類型多,比例要超過二比一。

  對于程序員來說,Java類庫中的絕大多數(shù)公共方法好像為每一個可能的失敗都聲明了已檢查異常。例如,java.io包對已檢查異常IOException的依賴性特別大。至少63個Java庫包直接或間接通過其數(shù)十個子類之一發(fā)布了此異常。

   I/O失敗很嚴重但也很少見。另外,程序代碼通常沒有能力從失敗中恢復(fù)。Java程序員發(fā)現(xiàn)他們必須提供IOException和類似在簡單的Java 庫方法調(diào)用時可能發(fā)生的不可恢復(fù)的事件。捕捉這些異常只會打亂原有簡潔的代碼,因為捕捉塊并不能改善此類情況。而不捕捉這些異常可能會更糟糕,因為編譯器 要求將這些異常加入到方法所拋出的異常列表中。這公開了一些實現(xiàn)細節(jié),優(yōu)秀的面向?qū)ο笤O(shè)計自然會將這些細節(jié)隱藏起來。

  這種無法成功的情況導(dǎo)致許多嚴重違反Java編程模式的異常處理。當今的程序員經(jīng)常被告誡要提防這些情況。同樣,在創(chuàng)建工作區(qū)方面也產(chǎn)生大量正確和錯誤的建議。

  一些Java天才開始質(zhì)疑Java已檢查異常模型是否是一次失敗的嘗試。可以確定某個地方出了問題,但是這和Java語言中的異常檢查無關(guān)。失敗的原因是Java API設(shè)計人員的思考方式,即他們認為大多數(shù)失敗情況都相同,并且可以用相同類型的異常來傳達。

錯誤和意外事件

  假想金融應(yīng)用軟件中的CheckingAccount類。CheckingAccount屬于客戶,維護當前余額,并且可以接受存款,根據(jù)支票 接受終止支付命令,以及處理入帳的支票。CheckingAccount對象必須協(xié)調(diào)并發(fā)線程的訪問,因為每一個線程都可以改變它的狀態(tài)。 CheckingAccount的processCheck()方法將Check對象作為參數(shù),從賬戶余額中正常扣除支票金額。但是調(diào)用 processCheck()的支票結(jié)算客戶端必須為兩類意外事件做好準備。首先,CheckingAccount 可能有為支票注冊的終止支付命令。第二,賬戶中可能沒有足夠的資金來支付支票金額。

  所以,processCheck()方法使用三種可 能的方式來響應(yīng)其調(diào)用者。正常的響應(yīng)方式是支票得到處理,在方法簽名中聲明的結(jié)果返回給調(diào)用服務(wù)。這兩類意外事件響應(yīng)代表了金融領(lǐng)域非常真實的情況,它們 需要與支票結(jié)算客戶端進行通信。所有這三種processCheck()響應(yīng)都是為模仿典型的支票賬戶行為而精心設(shè)計的。

  在Java中 表示意外事件響應(yīng)的通常方法是定義兩種異常,即StopPaymentException和InsufficientFundsException。客戶 端忽略這兩個異常是不正確的,因為在應(yīng)用程序正常操作時會被拋出這兩個異常。這兩個異常有助于表達方法的所有行為,和方法簽名一樣十分重要。

  客戶端可以輕松地處理這兩類異常。如果終止支票的支付,客戶端可以取得支票進行特殊處理。如果沒有足夠的資金,為支付此支票,客戶端將從客戶的儲蓄帳戶中轉(zhuǎn)移資金,并重新嘗試。

  這些意外事件可以預(yù)見,它是使用CheckingAccount API的自然結(jié)果。它們并不表示軟件或執(zhí)行環(huán)境的失敗。將這些異常條件與實際的失敗對比,實際的失敗是由于CheckingAccount類的內(nèi)部實現(xiàn)細節(jié)問題造成的。

   假設(shè)CheckingAccount在數(shù)據(jù)庫中維持持久的狀態(tài)并使用JDBC API進行訪問。在該API中,幾乎每一個數(shù)據(jù)庫訪問方法都有失敗的可能性,但原因與CheckingAccount實現(xiàn)無關(guān)。例如,有人會忘記打開數(shù)據(jù) 庫服務(wù)器、不小心拔下了網(wǎng)線,或改變了訪問數(shù)據(jù)庫的密碼。

  JDBC依靠單獨的已檢查異常SQLException來報告一切可能的錯 誤。大多數(shù)錯誤都與數(shù)據(jù)庫的配置、連接和硬件設(shè)備有關(guān)。processCheck()方法并不能以有意義的方式處理這些異常條件。很遺憾,因為 processCheck()至少知道它自己的實現(xiàn)方式。調(diào)用堆棧中的上游方法能夠處理這些問題的可能性會更小。

  CheckingAccount示例解釋了導(dǎo)致方法執(zhí)行不能返回預(yù)期結(jié)果的兩個基本原因。下面首先介紹一些描述性術(shù)語:

意外事件

   是一種可以預(yù)見的情況,要求方法做出某種響應(yīng),以便能夠表達方法所期望的目的。方法的調(diào)用者預(yù)見這些情況并采取策略應(yīng)付這些情況。

錯誤

   是一種計劃外的情況,它阻止方法達到其預(yù)期目的,并且如果不引用方法的內(nèi)部實現(xiàn),則無法描述這種情況。

  從這兩個術(shù)語來看,終止支付命令和透支是processCheck()方法兩個可能的意外事件。SQL問題代表了可能的錯誤異常條件。processCheck()的調(diào)用者應(yīng)當提供一種處理意外事件的方式,但當錯誤發(fā)生時,并不能合理地處理該錯誤。

映射Java異常

  對于意外事件和錯誤,思考其原因?qū)⒂兄跒閼?yīng)用程序架構(gòu)中的Java異常建立約定。

異常條件 意外事件 錯誤
認為是(Is considered to be) 設(shè)計的一部分 難以應(yīng)付的意外
預(yù)期發(fā)生(Is expected to happen) 有規(guī)律但很少發(fā)生 從不
誰來處理(Who cares about it) 調(diào)用方法的上游代碼 需要修復(fù)此問題的人員
實例(Examples) 另一種返回模式 編程缺陷,硬件故障,配置錯誤,文件丟失,服務(wù)器無法使用
最佳映射(Best Mapping) 已檢查異常 未檢查異常

  意外事件異常條件完美地映射到Java已檢查異常。由于它們是方法語義契約中不可或缺的一部分,因此必須借助編譯器來確保問題得到了處理。如果 開發(fā)人員堅持在編譯器有問題時處理或聲明意外事件異常,此時編譯器會成為一種阻礙,可以斷定此軟件設(shè)計必須進行部分重構(gòu)。這其實是一件好事。

   錯誤條件對編程人員來說能夠引起關(guān)注,而對于軟件邏輯卻并非如此。“軟件診斷學(xué)家”收集錯誤信息以診斷和修復(fù)引起錯誤發(fā)生的根源。因此,未檢查Java 異常是錯誤的完美表現(xiàn)方式,它們可以使錯誤通知完整地過濾調(diào)用堆棧上的所有方法,傳遞到專門用于捕捉錯誤的層,捕獲其中所包含的診斷信息,并為此活動提供 一份受約束的合理結(jié)論。錯誤產(chǎn)生方法并不需要聲明,上游代碼也不需要捕獲它們,方法的實現(xiàn)得到了有效的隱藏——產(chǎn)生最少的代碼混亂。

  較 新的Java API(比如Spring Framework和Java Data Object庫)很少或根本不依賴于已檢查異常。Hibernate ORM framework從release 3.0起重新定義了關(guān)鍵設(shè)備,以免于使用已檢查異常。這反映了由這些框架報告的絕大部分異常異常條件是不可恢復(fù)的,這些異常源于方法調(diào)用的不正確編碼或數(shù) 據(jù)庫服務(wù)器失效等基本組件原因。實際上,強制調(diào)用者去捕捉或聲明這樣異常幾乎沒有任何益處。

架構(gòu)中的錯誤處理

   在架構(gòu)中有效處理錯誤的第一步是承認處理錯誤的必要性。承認這一點對于工程師來說有困難,因為他們認為自己有能力創(chuàng)造無缺陷的軟件,并引以為豪。下面這些 理由可能有所幫助。首先,應(yīng)用程序開發(fā)會在常見錯誤上花費大量的時間。提供程序員產(chǎn)生的錯誤將使團隊診斷和修復(fù)這些錯誤變得十分簡單。第二,對于錯誤異常 條件過度使用Java庫中的已檢查異常將強制代碼來處理這些錯誤,即使調(diào)用順序完全正確。如果沒有適當?shù)腻e誤處理框架,由此產(chǎn)生的暫時異常處理將向應(yīng)用程 序中插入平均信息量。

  成功的錯誤處理框架必須達到四個目標:

  • 使代碼混亂最小化
  • 捕捉并保留診斷信息
  • 通知合適的人員
  • 比較得體地退出活動

  錯誤會分散應(yīng)用程序的真正目的。因此,用于錯誤處理的代碼數(shù)量應(yīng)當最小化,并在理想情況下,應(yīng)與程序的語義部分隔離。錯誤處理必須滿足糾錯人員 的需要。他們需要知道是否發(fā)生錯誤并且獲取相關(guān)信息以判斷錯誤原因。盡管從定義上說,錯誤不可恢復(fù),但可靠的錯誤處理措施將以得體地方式終結(jié)出現(xiàn)錯誤的活 動。

 

對于錯誤異常條件使用未檢查異常

   有許多原因使我們做出使用未檢查異常表示錯誤異常條件的架構(gòu)性決定。作為對編程錯誤的回報,Java運行時將拋出RuntimeException的子類 (比如ArithmeticException和ClassCastException),針對架構(gòu)設(shè)定先例。未檢查異常使上游方法擺脫了包含無關(guān)代碼的 要求,從而最大限度地減少了混亂。

  錯誤處理策略應(yīng)當承認Java庫和其他API中的方法可能使用已檢查異常來表示應(yīng)用程序環(huán)境下的錯誤異常條件。在這種情況下,采用架構(gòu)慣例在其出現(xiàn)的地方捕捉API異常,將它作為錯誤,并拋出未檢查異常來說明錯誤異常條件并捕捉診斷信息。

   在這種情況下拋出的特定異常類型應(yīng)當由架構(gòu)本身定義。不要忘記錯誤異常的主要目的是傳達診斷信息并記錄,以幫助開發(fā)人員發(fā)現(xiàn)問題產(chǎn)生的原因。使用多錯誤 異常類型可能有些過度,因為架構(gòu)會對它們進行完全相同的處理。在絕大多數(shù)情況下,把良好的描述性文本消息嵌入到單獨的錯誤類型中,便可完成此項工作。使用 Java的一般RuntimeException來表示錯誤條件很容易進行防御。從Java 1.4時起,RuntimeException同其他throwable類一樣,支持異常處理鏈式機制,允許設(shè)計人員捕捉并報告導(dǎo)致錯誤的已檢查異常。

   設(shè)計人員可以定義自己的未檢查異常進行報告錯誤。如果需要使用不支持異常鏈接機制的Java 1.3或更早版本,這一步是必需的。實現(xiàn)相似的鏈接功能去捕捉并轉(zhuǎn)換引起應(yīng)用程序錯誤的異常相當簡單。在錯誤報告異常中,應(yīng)用程序可能需要特別的行為。這 可能是為架構(gòu)創(chuàng)建RuntimeException子類的另一個原因。

建立錯誤屏障

   決定哪些異常要拋出以及何時拋出將成為錯誤處理框架的重要決定。同樣重要的問題是何時捕捉錯誤異常及其后如何做。這里的目標是使應(yīng)用程序的功能部分從處理錯誤的職責(zé)中分離出來。關(guān)注點分離通常是比較好的做法。負責(zé)處理錯誤的中央設(shè)備將為您帶來很多的好處。

   在錯誤屏障(fault barrier)模式下,任何應(yīng)用程序組件都可以拋出錯誤異常,但只有作為“錯誤屏障”的組件才可以捕捉到錯誤異常。開發(fā)人員為了處理錯誤問題在應(yīng)用程序 中插入了大量復(fù)雜代碼,而采用此模式可消除大部分此類代碼。從邏輯上講,錯誤屏障存在于靠近調(diào)用堆棧的頂端。在這里,它可以阻斷異常向上傳播,以避免觸發(fā) 默認動作。默認動作根據(jù)應(yīng)用程序類型的不同而不同。對于獨立的Java應(yīng)用程序來說,默認動作意味著終止活動線程。對于駐留在應(yīng)用服務(wù)器上的Web應(yīng)用程 序,默認動作意味著應(yīng)用服務(wù)器會向瀏覽器發(fā)送不友好的(且令人為難的)響應(yīng)。

  錯誤屏障組件的首要職責(zé)是記錄包含在錯誤異常中的信息,以 便進行下一步行動。應(yīng)用程序日志是迄今為止做這件事情最理想的方法。異常的鏈信息、堆棧跟蹤等對于診斷專家來說都是有價值的信息。發(fā)送錯誤信息最差的地方 是通過用戶界面。將客戶牽涉到應(yīng)用程序的排錯過程中,將對開發(fā)人員或客戶沒有任何益處。如果開發(fā)人員真的把診斷信息添加到了用戶界面上,這說明開發(fā)人員的 記錄策略需要改進。

  錯誤屏障的下一個職責(zé)是以受控方式停止操作。這個職責(zé)的含義由應(yīng)用程序的設(shè)計決定,但是通常會涉及到為等待響應(yīng)的客 戶端發(fā)出總體響應(yīng)。如果應(yīng)用程序是Web service,這意味著使用soap:Server的和普通失敗消息將 SOAP 元素嵌入到響應(yīng)中。如果應(yīng)用程序與Web瀏覽器進行通信,屏障將安排發(fā)送普通的HTML響應(yīng),表示無法處理此請求。

   在Struts應(yīng)用程序中,錯誤屏障采用全局異常處理程序的形式,配置成可以處理RuntimeException的任何子類。錯誤屏障類將擴展 org.apache.struts.action.ExceptionHandler,在需要實現(xiàn)自定義處理時重寫方法。這將處理由于疏忽產(chǎn)生的錯誤條 件和處理Struts操作中明顯發(fā)現(xiàn)的錯誤條件。圖2顯示了意外事件異常和錯誤異常。

圖2 意外事件異常和錯誤異常

如果開發(fā)人員正在使用Spring MVC框架,簡單地擴展SimpleMappingExceptionResolver并進行配置使其能處理RuntimeExceptio及其子類,便 能建立起錯誤屏障。通過重寫resolveException()方法,在使用超類方法向發(fā)送普通錯誤顯示的查看組件發(fā)出請求之前,開發(fā)人員可以添加任何 自定義處理。

  當架構(gòu)包含錯誤屏障并且開發(fā)人員也意識到了它的存在時,編寫一勞永逸的錯誤異常處理代碼的吸引力急劇下降。結(jié)果是在應(yīng)用程序中產(chǎn)生更簡潔和更易維護的代碼。

架構(gòu)中的意外事件處理

  隨著錯誤處理委托給屏障,主要組件之間的意外事件通信變得更加簡單。意外事件代表了另一種方法結(jié)果,此結(jié)果與主要返回結(jié)果同樣重要。因此,已檢 查異常類型是傳遞意外事件條件存在性并提供對付異常條件所需信息的良好工具。最佳實踐是借助Java編譯器來提醒開發(fā)人員他們正在使用API的所有方面, 同樣需要提供方法結(jié)果的全部范圍。

  通過單獨使用方法的返回類型,可以傳遞簡單的意外事件。例如,返回null引用而非實際對象可以說明 此對象由于明確的原因而無法創(chuàng)建。Java I/O方法通常返回整數(shù)值-1,而不是字節(jié)值或字節(jié)計數(shù),用來表明文件的結(jié)束。如果方法的語義非常簡單允許這樣做,另一種返回值可以使用這種方式,因為它 們消除了由異常而帶來的開銷。不利方面是方法調(diào)用者負責(zé)檢測返回值,來查看它是主要結(jié)果還是意外事件結(jié)果。然而,編譯器并不強制調(diào)用者做這樣的測試。

   如果方法具有void返回類型,異常將是表明意外事件發(fā)生的唯一方法。如果方法返回對象引用,則返回值所表達的意思僅限于兩個值(null和non- null)。如果方法返回整數(shù)值,通過選擇確保與主要返回值不相沖沖突的值,就可以表達數(shù)個意外事件條件。但是現(xiàn)在已經(jīng)進入了錯誤代碼檢查的范疇,這是 Java異常模型需要避免的情況。

提供有用的信息

   定義不同的錯誤報告異常類型沒有任何道理,因為錯誤屏障會對它們進行同樣的處理。意外事件異常差異很大,因為它們會向方法調(diào)用者傳達各種條件。您的架構(gòu)可能明確指定這些異常都應(yīng)該擴展java.lang.Exception或指定的基類。

   不要忘記這些異常是完整的Java類型,可以調(diào)整特定的字段、方法以及為特殊目的而構(gòu)建的構(gòu)造函數(shù)。例如,假想的CheckingAccount processCheck()方法拋出的InsufficientFundsException類型可能包括OverdraftProtection對 象,此對象能夠轉(zhuǎn)移資金以彌補另一個賬戶的資金短缺,此賬戶的身份取決于設(shè)置核算賬戶的方式。

記錄還是不記錄

   記錄錯誤異常有實際意義是因為它們的目的是吸引開發(fā)人員去注意需要糾正的情況。但這并不適用于意外事件異常。它們可能代表相對少見的事件,但是在應(yīng)用程序 的生命周期內(nèi),這些意外事件依然會發(fā)生。它們表明了如發(fā)生異常應(yīng)用程序?qū)凑掌湓O(shè)計意圖進行工作。按照慣例,在意外事件捕捉模塊中加入記錄代碼只會增加混 亂代碼而沒有任何益處。如果意外事件表示重要事件,最好為方法產(chǎn)生一條記錄項,用于在拋出意外事件異常并通知其調(diào)用者之前記錄此事件。

異常方面

  在面向方面編程(Aspect Oriented Programming (AOP))中,錯誤和意外事件的處理是橫切關(guān)注點。例如,要實現(xiàn)錯誤屏障模式,所有參與的類都必須遵守公共約定:

  • 錯誤屏障方法必須駐留在遍歷參與類的方法調(diào)用的頭部。
  • 它們都必須使用未檢查異常來表示錯誤條件。
  • 它們都必須使用特定的未檢查異常類型,以便錯誤屏障能夠接收到。
  • 它們都必須從較低層方法中捕捉并轉(zhuǎn)換已檢查異常,這些異常在它們的執(zhí)行環(huán)境中被視為錯誤。
  • 它們不能干擾錯誤異常到屏障的傳播。

  這些關(guān)注點跨越了其他不相關(guān)類的邊界。結(jié)果產(chǎn)生了少量分散錯誤處理代碼并致使屏障類與參與者之間的隱式耦合(盡管對于完全沒有使用模式來說是一 次重大改進)。AOP允許將錯誤處理關(guān)注點封裝到應(yīng)用于參與類的公共Aspect中。Java AOP框架(比如AspectJ和Spring AOP)把異常處理作為聯(lián)接點,錯誤處理行為(或建議)能夠附加到上面。這樣,在錯誤屏障模式中綁定參與者的慣例就有所放寬。錯誤處理現(xiàn)在可以存在于獨立 的非內(nèi)聯(lián)方面(out-of-line aspect)中,避免了將“屏障”方法置于方法調(diào)用序列的前面。

  如果開發(fā)人員在架構(gòu)中使用AOP,錯誤和意外事件的處理是方面在整個應(yīng)用程序中應(yīng)用的理想候選對象。完全探究錯誤和意外事件處理在AOP中如何運作,這是個令人感興趣的話題,留作以后討論。

結(jié)束語

  盡管Java異常模型在其生命周期內(nèi)已經(jīng)引發(fā)了激烈的爭論,但是當Java異常模型運用得當時,將會帶來巨大的價值。作為架構(gòu)師,應(yīng)當決定如何 建立最大限度利用模型的慣例。思考一下錯誤和意外事件異常能夠幫助開發(fā)人員做出正確的選擇。Java異常模型使用得當,將保持應(yīng)用程序的簡潔性、可維護性 和正確性。把面向方面編程技術(shù)的錯誤和意外事件處理作為橫切關(guān)注點,可為應(yīng)用程序的架構(gòu)帶來某些明顯的優(yōu)勢。