2013-07-31 26 views
4

所以這是關於我最近被問到的面試問題。面試官通過詢問我們如何創建我們的自定義例外來開始這項工作。在回答這個問題時,他問我如何創建一個RunTimeExceptions。我說我們會以創建選中的例外的方式創建它們。只是我們的自定義異常會從RunTimeException類延伸。然後他問你會在什麼情況下創建自己的RunTimeException。現在我想不出一個好的答案。在我的任何項目中,我們都創建了自定義RunTimeExceptions。自定義運行時異常

我也認爲我們不應該創建RunTimeExceptions。 JVM只能以有限的方式出現故障,並能很好地處理它們。在編寫應用程序時,我們無法預測哪些運行時異常會發生,因此我們不需要處理它們。如果我們可以預測這些條件,那麼它們不是RunTimeExceptions。既然我們既不需要新的運行時異常,也不需要處理runtimeexceptions,爲什麼我們需要創建一個自定義的RunTimeException。我們可以預先考慮的所有可能的故障條件都應該在編譯時處理,並且這將是一個檢查的異常。對?只有在編譯時無法處理的事情和依賴於運行時事情的事件纔會進入RunTimeExceptions類別。

即使我們編寫自定義RunTimeExceptions,然後自定義方法應該拋出RunTimeException - 我們如何確保該方法將拋出該特定的RunTimeException。我們如何做這個映射。對我來說似乎不可能。

我在這裏錯過了很多東西嗎?友善的建議。

謝謝, 陳。

+0

現代編程技術建議使用** unchecked **異常。你可以閱讀爲什麼,在漂亮的文章[這裏](http://johnpwood.net/2008/04/21/java-checked-exceptions-vs-runtime-exceptions/)。 – agad

回答

6

我認爲面試官試圖瞭解你是否理解運行時異常的目的,它表示程序員的錯誤(與應用程序異常相反,這表示執行環境存在問題)。

只要您的方法需要發出相當於編程錯誤的條件,您就可以創建RuntimeException的子類,並且需要提供有關異常描述錯誤的其他信息。

例如,考慮允許您將數據存儲在稀疏多維數組中的類。這種類可能提供的API之一是一個獲取一系列索引的getter。索引的數量需要等於數組中的維數,並且每個索引必須在其範圍內。提供一個元素數量不正確的數組參數,或者在其邊界外有一個或多個元素,這是一個編程錯誤。您需要用運行時異常來發信號。如果您想要發出此錯誤的信號,並提供完整的錯誤信息,您的子類IllegalArgumentExceptionRuntimeException的子類)將構建您自己的異常。

最後,還有一個情況,當你想繼承RuntimeException:當你應該提供一個「正規」的例外,但你不希望你的用戶來包裝你的API調用每一個try/catch塊。在這樣的情況下,可以更換一個方法

void performOperation() throws CustomApplicationException; 

用對方法

boolean canPerformOperation(); 
void performOperation(); 

第一種方法告訴來電者,這是安全地調用當前狀態的第二種方法;它從不拋出異常。

第二種方法僅在第一種方法返回false的狀態下失敗,從而使編程錯誤失敗,從而證明使用RuntimeException來發信號通知這樣的失敗。

+0

我的方式太缺乏經驗,無法評論@JonSkeet或您的傳奇人物的答案!但關鍵是他可以將自定義消息附加到運行時異常,爲什麼要創建一個新類? – NINCOMPOOP

+1

@TheNewIdiot能夠捕捉它,如果你想或以其他方式輕鬆處理它 – agad

+0

@agad他甚至可以捕捉運行時?他不能嗎? – NINCOMPOOP

1

我認爲當你創建自定義異常時,請不要繼承RuntimeException,它違背了創建自定義異常的全部目的。

即使我們編寫自定義RunTimeExceptions,然後自定義方法應該拋出該RunTimeException - 我們如何確保該方法將拋出該特定的RunTimeException。

這裏的要點實際上是方法的調用者不需要環繞在try-catch塊中,因爲它不是檢查的異常。除非你有一個很好的理由拋出一個自定義的未經檢查的異常,比方說,爲了提供額外的日誌等自定義信息,不要這樣做。另一個不好的實現是有時你只想在你的代碼中捕獲被檢查的異常,並拋出自定義的未經檢查的異常來擺脫調用者代碼中的所有try-catch。

+1

它以什麼方式「擊敗創建自定義異常的全部目的」?這聽起來像你正在考慮編譯時檢查是創建異常子類的唯一好處,我不同意這一點。 –

+0

謝謝。我這麼認爲,但自從面試官問了我這件事以來,由於我們已經討論了5分鐘以上的討論,所以我想我會檢查我的任何房屋是否存在根本性缺陷或者我是否在這裏丟失了某些東西。 – Chan

1

你會創建自己的RuntimeException子類,如果:

  • 你不希望它成爲一個檢查異常,因爲你不希望呼叫者明確捕獲異常。 (就我個人而言,我相信檢查的異常在標準庫中被過度使用。)
  • 您仍想提供更多信息而不僅僅是一條消息(只是類型本身是日誌中有用的起點)。

HibernateException就是這個在Hibernate ORM中的一個例子。

+2

如果我沒弄錯RuntimeExceptions也用於調用方在發現拋出異常時沒有任何優勢,因爲可能有些東西是不可恢復的。 –

+0

@NarendraPathai:這取決於你發現拋出異常的意思。我明確地涵蓋了呼叫者不會*捕捉第一個項目符號中的例外情況。 –

4

檢查異常與未檢查異常是Java開發人員長期爭論的話題。我不是在這裏點燃火焰,而只是想與你分享我在工作中如何使用它。

例如,另一個服務調用我的服務器以獲取客戶信息。輸入是的customerID,我會返回一個客戶對象

// Web Service interface 
public CustomerInfo getCustomerInformation(int customerId, int securityToken) { 
    check(securityToken); 
    Customer customer = merchantService.getCustomer(customerId); 
    return customer.getInfo(); 
} 

// MerchantService 
public Customer getCustomer(int customerId) { 
    return customerService.getCustomer(customerId); 
} 

如果系統無法找到特定的顧客會發生什麼?當然,它會拋出一個異常或返回null。但是返回null是不好的,因爲每次從服務調用時它都會讓你檢查null。所以,我去引發異常:

// Customer service 
public Customer getCustomer(id) { 
    Customer customer = getCustomerFromDB(); 
    if (customer == null) throw CustomerNotExistedException(); 
    return customer; 
} 

現在的問題是CustomerNotExistedException是否是異常或一個RuntimeException。如果它是一個檢查的異常,則需要在調用getCustomer的函數中捕獲並處理它。這意味着您必須在MerchantService上捕獲它。但是,您只需要在WebService級別生成一個404錯誤,以便在MerchantService上捕獲該錯誤不會再發生異常情況。它污染了代碼。

在一般情況下,我經常使用RuntimeException讓一些異常「冒泡」到它們可以處理的級別。

僅供參考,我會推薦本書Clean code from Robert C. Martin。它很好地解釋了我們應該如何使用異常來處理Java中的錯誤。