2012-09-24 44 views
24

在過去,我讀到噸代碼等的方法:是「拋出的Throwable」良好做法

public Object doSomething() throws Throwable { 
    ... 
} 

它是常見的做法,以做到這一點?

什麼是優點&缺點?

catchprintStackTrace()是不是更好?

throws Trowable在我看來,像得到Exception-回事方法

  • 編輯


    1. 處理預期異常的 「橙劑」 的方式扔未爆(一個接一個)

    2. 做一個錯誤

    不綱領性護理的路要走?

  • +1

    可能這會給你一個解釋:http://stackoverflow.com/questions/498217/when-should-throwable-be-used-instead-of-new-exception – Serge

    +0

    「throws Throwable」更常用於SDK和框架定義。以下是Android測試框架中使用它的一個示例:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/test/ InstrumentationTestCase.java#InstrumentationTestCase –

    回答

    42

    你不應該扔Throwable。這是爲什麼。

    Throwable是可以拋出的東西的層次結構的頂部,它由ExceptionsErrors組成。由於Errors的定義是由不可挽回的條件引起的,因此將它們包含在方法聲明中是毫無意義的。那隻剩下Exception

    你應該throws Exception,而不是宣佈你的方法。


    請注意,範圍越窄越好throws

    如果您的方法不生成異常,而是調用聲明爲throws Exception的其他代碼,並且希望異常滲透調用堆棧,則聲明您的方法爲throws Exception即可。

    如果你的方法是產生異常,然後聲明較窄的範圍,例如throws IOException, MyProcessingException

    +2

    我想補充一點,如果你正在滲透的異常可以通過代碼在鏈上某個點糾正,那麼可以聲明拋出Exception(),但如果它不是代碼用來修復自身的東西,那麼你應該捕獲異常並將它們重新拋出爲RuntimeExceptions。在這種情況下,你不會在你的方法上聲明它會拋出一個運行時異常,而是你用javadoc來記錄它。 –

    1

    在功能上,它與throws Exception等效,因爲錯誤未被選中。

    我沒有理由聲明一個方法來拋出Throwable。但是,這並不意味着catch和printStackTrace是一個很好的選擇。

    通常情況下,你想趕上throwables,你可以做些合理的事情。

    代碼拋出一個拋出你不指望應該爆炸光榮,所以你可以看到錯誤並修復錯誤。

    +2

    您可以拋出Throwable的子類,它不是一個異常或錯誤,但不建議這樣做。 ;) –

    +0

    當然是對的。我真的希望這在實踐中永遠不會起作用。 – Buhb

    +1

    Throwable的子類按Throwable進行檢查(Error和RuntimeException的子類除外) –

    0

    您是否特意提問Throwable?如果是這樣,那麼這是不好的做法。它不會爲類(方法)用戶提供任何有用的信息。

    1

    這是常見的做法嗎?

    在JDK中很少見。當不清楚如何處理檢查的異常時,主要使用它。

    什麼是優點&缺點?

    的優點是,你得到你的代碼,而無需擔心檢查exception.s

    的利弊編譯是例外,你應該處理被忽略。

    捕獲和printStackTrace()不是更好嗎?

    無法處理的異常通常會打印出來,所以捕捉它們並沒有多大幫助。

    你應該捕捉異常時,你可以這樣做增加一些價值和異常時不能添加到throws條款。

    8

    這是一個加載的問題。這不是關於異常處理,而是關於代碼可讀性。

    這取決於你來自哪裏,讓你的代碼示例。專業人士更傾向於在拋出某種方法時更加具體。主要原因是它使您的API更具可讀性。例如,如果您的方法拋出Throwable,那麼基本上就意味着任何事情都可能發生,並且您的方法不想處理它,無論如何。但實際上,只有東西數量有限,可能會發生:

    • 無論檢查從其他電話產生的異常,你在你的方法使
    • 不管檢查你根據自己的主張投擲目的例外
    • 無論未經檢查的異常你不打算爲
    • 錯誤(java.lang.Error)是更全局的JVM和環境

    通過專門STA除了要拋出的異常之外,還要告訴API的用戶他們應該警惕哪些內容。例如,當您使用InputStream,你會發現大多數方法拋出至少java.io.IOException,它給你你應該看什麼有用的信息。

    編碼時,作爲一般規則,你要儘量保持你的API的表現越好。你基本上有一行代碼來顯示一個方法的公共API(也就是我的猜測),所以你希望它完全表達(返回類型,名稱,參數,但也拋出異常)。

    至於捕捉拋出異常並打印堆棧跟蹤,我會說,你不應該捕獲異常除非你能做些什麼。相反,讓它將調用堆棧捲起來,直到某個類抓住它來做一些事情。有時候,它可能會一直延伸到你的主類,我想它將不得不趕上它並打印棧跟蹤作爲最後的手段。基本上,如果你不能對異常採取行動,那就讓它上升到調用堆棧。另外,你發現自己處於一種你應該摒棄例外的情況下(即抓住它但不採取任何行動),這是極其罕見的。遇到問題時,通常會遇到問題。

    這是一個有趣但有趣的article圍繞濫用異常處理一般。

    1

    這確實值得商榷。 拋出過多異常的方法會導致很多錯誤處理代碼。有些時候它不是有意的。

    但是因爲我不喜歡太多的異常在簽名並不意味着讓我們使用父母的所有異常,我們完成了!不起作用。

    什麼人可以做的是分類的例外,如BusinessExceptionServiceException所以,如果你有一個商業規則,它說,minimum balance in account can not be less than say 100$然後InsufficientBalance異常將會產生,這將是BusinessException

    孩子,所以你的方法會像

    public Object doSomething() throws BusinessException { 
    
    if(!hasMinimumbalance()) 
        { 
        throw new InsufficientBalance(ErrorCode); 
        } 
    } 
    

    這將完成是俱樂部有關的異常在一起,每當API用戶要檢測異常的具體錯誤,那麼他就可以做到這一點,否則一般的錯誤處理是可能的。

    核心在這裏點是你應該顯示該您已經用完了平衡的,你不能取錢用戶UI

    您可以在更大的方面說,以顯示人類可讀的形式錯誤確實需要分離例外。

    0

    Throwable(and catch)Throwable(或Exception)通常是不好的做法,因爲它會覆蓋你可能想要捕捉的任何特定異常。然後,你將不得不求助於醜象下面這樣:

    public void myMethod() throws Throwable { 
        if (x) { 
         throw new MyException1(); 
        } 
        if (y) { 
         throw new MyException2(); 
        } 
    } 
    
    public void callingMethod() { 
        try { 
         myMethod(); 
        } 
        catch(Throwable t) { 
         if (t instanceof MyException1) { 
          // handle exception 1 
         } 
         else if (t instanceof MyException2) { 
          // handle exception 2 
         } 
         else { 
          // handle other exceptions 
         } 
        } 
    } 
    

    這是容易出錯(和CheckStyle的標記作爲代碼違例)。這是很preferrable有這樣的代碼:只要通過喚起的printStackTrace(

    public void myMethod() throws MyException1, MyException2 { 
        if (x) { 
         throw new MyException1(); 
        } 
        if (y) { 
         throw new MyException2(); 
        } 
    } 
    
    public void callingMethod() { 
        try { 
         myMethod(); 
        } 
        catch(MyException1 e) { 
         // handle exception 1 
        } 
        catch(MyException2 e) { 
         // handle exception 2 
        } 
    } 
    

    處理異常)通常不是一個好主意。 printStackTrace()將堆棧跟蹤發送到標準錯誤,根本不可讀取。更好的選擇是使用應用程序的日誌工具(如log4j)來報告異常。即使那樣,只是記錄它可能是不夠的。

    我的經驗法則是:

    如果你可以在本地處理異常,這樣做。例如解析字符串爲整數,你可以趕上NumberFormatException異常,並返回默認值時:

    prvate int parseAmount(String amountValue) { 
        int amount; 
        try { 
         amount = Integer.parseInt(amountValue); 
        } 
        catch(NumberFormatException e) { 
         // default amount 
         amount = 0; 
        } 
        return amount; 
    } 
    

    如果你不能處理本地異常,考慮是否應公開正被拋出的異常類型。如果這個類型是一些不起眼的(實現相關的)類型,然後在自己的泛型類型的異常包裹它可能是一個好主意:

    private Customer getCustomer(int customerId) throws ServiceException { 
        try { 
         return customerService.getCustomer(customerId); 
        } 
        catch(CustomerServiceSpaghettiTangledException e) { 
         throw new ServiceException("Error calling the customer service", e); 
        } 
    } 
    

    這裏ServiceException「是您創建異常的子類。 Spring還專門爲此提供了一個exception hierarchy

    通過包裝異常,您可以隱藏實現細節,使您的服務層更簡單易用。

    如果你決定從你的方法拋出異常,你需要在callstack中'更高'處理它。這可能是Web應用程序中的一個通用錯誤頁面,指出發生錯誤並可能提供錯誤消息或代碼。在某些情況下,較高級別的代碼可以嘗試重試或可能以其他方式獲得所需的結果。

    1

    在一些罕見的情況下,可以接受Throwable s。例如,Spring AOP中的@Around通知通常被聲明爲拋出Throwable

    下面的例子是從Spring AOP docs逐字複製:

    import org.aspectj.lang.annotation.Aspect; 
        import org.aspectj.lang.annotation.Around; 
        import org.aspectj.lang.ProceedingJoinPoint; 
    
        @Aspect 
        public class AroundExample { 
    
         @Around("com.xyz.myapp.SystemArchitecture.businessService()") 
         public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { 
          // start stopwatch 
          Object retVal = pjp.proceed(); 
          // stop stopwatch 
          return retVal; 
         } 
    
        } 
    

    爲什麼doBasicProfiling聲明瞭一個Throwable?由於原始方法(即執行連接點)可能會拋出Error,RuntimeException或檢查的異常。所以聲明doBasicProfiling拋出Throwable纔有意義。