引言:高级语言中的异常处理很好用,对于有可能出错的代码我们用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;}
正像老板说的:
新闻热点
疑难解答