今天,你Try-Catch了吗?

 

引言:
高级语言中的异常处理很好用,对于有可能出错的代码我们用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/catch
00: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: 68
Without try catch: 34

 

结果显示好像有影响啊,两倍啊!高兴太早了,把for循环里的计算语句稍微做下改动,变为

c += i * (2 * (int)Math.Floor((double)i));

 

结果显示为:

Output:
With try catch: 640
Without 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;
}

 

正像老板说的:



 

posted @ 2014-04-22 19:47  苏大小飞  阅读(362)  评论(0编辑  收藏  举报