引言:高級語言中的異常處理很好用,對于有可能出錯的代碼我們用Try-Catch包起來,就能保證系統健壯的運行了,但是你的Try-Catch用對了嗎?
今天code review的時候,老板給我提了個問題,讓我不要用Try-Catch。原話是這樣的:

然后我就想,為什么不讓try catch啊,如果不try catch程序出錯時不就down了嗎,用戶連出錯信息都得不到,這樣的系統也太不友好了吧?
然后老板又跟我解釋了,原話如下:

老板在西雅圖的微軟干了10來年,我是還沒畢業的菜鳥,對老板說的話自然是不敢貿然懷疑的,于是乖乖改了代碼。但是不安分的內心還是驅使我到網上搜了一下,不搜不知道,原來網上對于這個問題早已是討論了千八百遍。
總結了10幾個來自StackOverflow的回答,大致意思如下:
問題一:使用try catch會不會影響程序運行效率?
解釋:
static public void Main(string[] args){ Stopwatch w = new Stopwatch(); double d = 0; w.Start(); for (int i = 0; i < 10000000; i++) { try { d = Math.Sin(1); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } w.Stop(); Console.WriteLine(w.Elapsed); w.Reset(); w.Start(); for (int i = 0; i < 10000000; i++) { d = Math.Sin(1); } w.Stop(); Console.WriteLine(w.Elapsed);}Output:00:00:00.4269033 // with try/catch00:00:00.4260383 // without.
這個實例說明了并不像有的人說的那樣,try catch并不會影響代碼的執行效率。但是注意,上面這個實例catch塊里并沒有rethrow;繼續看下面這個示例:
PRivate void TryCatchPerformance(){ int iterations = 100000000; Stopwatch stopwatch = Stopwatch.StartNew(); int c = 0; for (int i = 0; i < iterations; i++) { try { // c += i * (2 * (int)Math.Floor((double)i)); c += i * 2; } catch (Exception ex) { throw; } } stopwatch.Stop(); WriteLog(String.Format("With try catch: {0}", stopwatch.ElapsedMilliseconds)); Stopwatch stopwatch2 = Stopwatch.StartNew(); int c2 = 0; for (int i = 0; i < iterations; i++) { // c2 += i * (2 * (int)Math.Floor((double)i)); c2 += i * 2; } stopwatch2.Stop(); WriteLog(String.Format("Without try catch: {0}", stopwatch2.ElapsedMilliseconds));}Output:With try catch: 68Without try catch: 34
結果顯示好像有影響啊,兩倍啊!高興太早了,把for循環里的計算語句稍微做下改動,變為
c += i * (2 * (int)Math.Floor((double)i));
結果顯示為:
Output:With try catch: 640Without try catch: 655
希望破滅了,看來有沒有影響還有try塊里執行的內容有關。但是大量的實驗說明影響是很小的。
問題二:既然try-catch不影響效率,那么為什么不提倡像下面這樣使用?
public static string SerializeDTO(DTO dto) { try { xmlSerializer xmlSer = new XmlSerializer(dto.GetType()); StringWriter sWriter = new StringWriter(); xmlSer.Serialize(sWriter, dto); return sWriter.ToString(); } catch(Exception ex) { throw ex; }}解釋:
首先要講一個問題:如果這段代碼的try塊里出了問題,那么程序是要down掉的,因為在catch塊里throw了Exception,并沒有消化掉,如果去掉這個throw 那么在try塊出問題的情況下程序也不會down掉了。像下面這樣:
public static string SerializeDTO(DTO dto) { try { XmlSerializer xmlSer = new XmlSerializer(dto.GetType()); StringWriter sWriter = new StringWriter(); xmlSer.Serialize(sWriter, dto); return sWriter.ToString(); } catch(Exception ex) { }}雖然這樣寫程序不會down掉,但有意思的是:這種寫法也不推薦。
第一種寫法不推薦的原因如下:try塊里拋出的異常信息(有可能是SqlException之類的)被catch塊包裝成了Exception重新拋出,屏蔽掉了原本的出錯信息,在fix bug的時候不好找原因。第二種寫法不推薦的原因如下:這種寫法程序不會down掉,因為catch塊把出錯信息消化掉了。這樣有很不好的后果是:debug的時候找不到真正的錯誤源頭在哪里!!問題三:提倡的寫法是什么?
答案:
try { ... }catch { throw; }但是這樣寫和不用try-catch有什么不同么?根本沒有!所以通常的做法是如果需要log出錯信息時,才使用try-catch,像下面這樣寫:
try { // code that may throw exceptions }catch { // add error logging here throw;}正像老板說的:

新聞熱點
疑難解答