2012-02-29 75 views
3

我試過在其他線程上尋找這個答案,但到目前爲止,我只看到線程狀態,捕獲Throwable是壞的。我的問題是,是否有一個原因,你會想要做到這一點,然後在catch塊中什麼也不做,除了打印堆棧跟蹤?爲什麼你會捕獲Throwable並且什麼也不做,但是打印堆棧跟蹤?

我最近被帶到一個項目中,並完成了清理RESTful服務的現有類錯誤處理的任務。一些輔助服務類有try/catch塊,只有趕上了Throwable並將其打印出堆棧跟蹤,如下所示:

class MainService { 

    SubService1 s1; 
    SubService2 s2; 

    public doMainService() { 
    } 

} 


class SubService1 { 

    public int findSomething() { 

    try { 
     // Do Something 
    } catch (Throwable t) { 
     t.printStackTrace(); 
    } 
    } 
} 

class SubService2 { 

    public int findSomethingElse() { 

    try { 
     // Do Something 
    } catch (Throwable t) { 
     t.printStackTrace(); 
    } 
    } 

} 

是否存在,這是可以接受的情況下?方法拋出異常並且沒有try/catch塊會更好嗎?

+1

沒有ESP和直接鏈接到寫這個人的人...沒有人回答這個問題。大多數*可能*回答?糟糕或懶惰的程序員。其他可能性?未完成/匆忙的代碼從未退出調試階段。 – 2012-02-29 01:11:33

+0

這是一個有效的問題,特別是對於新手到Java的人。他/她問我們這些Java專家,如果這是有充分理由的話。 – 2012-02-29 01:17:47

+0

對不起,我想我應該更好地問這個問題,因爲不可能知道以前的程序員在想什麼。代碼運行良好,並且在代碼中有ExceptionMappers將異常映射到HTTP狀態代碼,這使得我更加困惑。 – punkconvoy 2012-02-29 01:17:54

回答

3

對於各種衆所周知的原因,這幾乎不是一個好的做法。

特別是,它不區分checkedunchecked例外和errors。更重要的是,這段代碼的一個作用是允許應用程序在異常處理程序之外執行,由於違反了不變量,這可能會導致各種奇怪的行爲。換句話說,由於捕獲到的異常可能實際上包括違反的斷言,編程錯誤,線程中斷,缺少的類,I/O錯誤,OOM條件,甚至是庫和虛擬機錯誤,程序狀態在異常處理程序之外實際上是不可預測的。

在一些罕見的情況下,廣泛的異常處理可能是有意義的。設想一個服務器處理多個獨立請求。由於在服務其中一個請求時遇到問題,您可能不希望崩潰。由於不依賴異常處理程序後留下的狀態,因此只需打印堆棧跟蹤並在服務器繼續服務其他請求時讓其他人進行調查。

即使在這些情況下,也應該仔細考慮是否有錯誤真的應該被抓住。

+0

我同意這不是一個好習慣。這是我永遠不會想的事,這就是我現在在這裏的原因。將它們移除並讓該方法拋出異常並讓這些問題向主服務冒泡是不是更好? – punkconvoy 2012-02-29 01:55:53

+0

是的,我也認爲讓異常正確傳播會更好。作爲額外的好處,這提供了一個機會來記錄應用程序中的異常使用情況,並減少異常處理程序的數量(在將來發生更改時有用)。請注意,根據應用程序的大小,這可能是一項重大努力。 – 2012-02-29 09:06:52

0

如果您不知道任何其他方式獲取堆棧跟蹤,並且想知道如何獲取當前位置,則可以這樣做。不是一個很好的理由,而是一個可能的理由。這似乎不符合你所看到的;你似乎已經給出了不會崩潰的代碼,但在錯誤處理方面也做得不好。

0

我用它來查看我的程序崩潰的確切位置。所以基本只是爲了調試。也只是爲了看看它是否按照預期的方式流動。

+0

對於你來說,要麼是在頂層,否則你會重新拋出。 – ninjalj 2012-02-29 01:53:11

2

我認爲人們這樣做的一個原因只是因爲Java強迫你圍繞調用try/catch塊引發的調用,或者將方法聲明添加到throws中。

如果你「知道」你將不會有異常發生,那麼這是一種防止它上升的方式(因爲如果你拋出,有人稱你的代碼需要包圍與一個try/catch等),但如果發生了什麼,它會轉儲它而不會崩潰。

+2

這是處理這種情況的一種可怕的方式。如果你知道它永遠不會拋出,那麼用一個UnsupportedOperationException包裝它並重新拋出它。這樣,如果它曾經拋過,你不會失去它。 'e.printStackTrace()'去stderr,它可能會去/ dev/null所有你知道的。 – jtahlborn 2012-02-29 04:08:09

+0

哦,這是可怕的做法,但這是一些人做的。 – scaryrawr 2012-02-29 13:09:53

+0

你的答案几乎聽起來像你認爲它是一個合理的解決方案,這就是爲什麼我評論。你應該把你的評論添加到你的答案中。 – jtahlborn 2012-02-29 16:17:09

0

他們可能希望看到堆棧跟蹤而不會崩潰程序。

例如,它可能適合由線程執行的代碼來記錄異常,但在線程不可接受時不會接受自從下一次迭代(例如線程正在從隊列中取出項目)時崩潰的情況,預期。這取決於用例,但對於服務器,您通常希望線程能夠防彈並記錄任何錯誤,而不是停止任何進一步處理(但用例可能會有所不同)。

0

我們遇到的最簡單的例子是關閉輸入流.Follwoing是InputStream類中的方法聲明。

公共無效的close()拋出IOException異常

Althoug有一個方法可行拋出一個異常,當我們調用這個方法這將是程序執行任何傷害。(因爲我們將不使用的InputStream進一步)在在這種情況下,我們只應記錄錯誤並繼續執行程序。但是,如果你發現了一個異常,它會改變對象的狀態,然後你必須考慮恢復代碼或停止執行。

0

千萬不要這樣做(e.printStackTrace())。許多IDE默認使用它,但它很可怕(許多應用程序使用stderr以無法訪問的方式重定向,因此從未見過)。經驗法則:

  • 如果你真正不關心異常(永遠,永遠,永遠,永遠會關心),抓住它,什麼也不做一個大註釋的說:「我們真的,真的如果你拋出這個異常,你永遠不會在意「
  • 如果你從不期望一個實際被拋出的異常(接口定義了一個檢查的異常,但你知道impl實際上並沒有拋出它),重新拋出異常就像new UnsupportedOperationException("this should never happen", t)(這樣,如果/當底層impl被改變時,你可以儘早發現它)
  • 如果您希望異常不太可能發生,並且您通常不會關心它,請使用適當的日誌記錄基礎結構(log4j,commons logging或java.util.logging)對其進行日誌記錄。這樣,如果你決定實際上關心異常畢竟,它很可能會使它在某個你可以看到的地方。