您的位置:首页 > 其它

try catch 语句好不好?

2016-06-12 23:24 246 查看
                                                                  try catch 语句好不好?

      在ITOOjava5.0代码走查中,有一个 细节,Try  catch 不是很建议用,如果是用了,又是为什么呢,对于这个进行

一个小的总结。

  一句话解释:

  

      try catch机制可以非常好。觉得try catch 不是很好的,可能是还没有发现她的好!

二、详细解释:
   1.程序要健壮,必须要设计报错机制。
     最古老,也是最常见的,比如:

bool CreateFile( );
//如果创建文件失败就返回false,否则返回true。


//如果创建文件失败就返回false,否则返回true。
这种报错方式,显然不好。因为它没有给出产生错误的具体原因。

2.改进:一个函数或过程,会因为不同的原因产生错误,报错机制必须要把这些错误原因进行区分后,再汇报。
比如:

<span style="font-size:18px;">int CreateFile():
//如果创建成功就返回1.
//如果是因为没有权限,导致失败,返回-1。
//如果是因为文件已经存在,导致失败,返回-2。
//如果是因为创建文件发生超时,导致失败,返回-3。</span>

这样看上去,比【1】要好些,至少指出了比较具体的失败原因,但是,还不够。

    3.很多情况下,函数需要把详细的原因,用字符串的方式,返回:
<span style="font-size:18px;">class Result
{
....int State;//同【2】
....string ErrorMessage;//如果失败,这里将给出详细的信息,如果有可能,应该把建议也写上去。
}

Result CreateFile();
//如果创建成功,返回的Result,State为1,ErrorMessage为null。
//如果是因为没有权限,导致失败,返回的Result,State为-1,ErrorMessage为"用户【guest】没有权限在【C:\】这个目录下创建该文件。建议您向管理员申请权限,或者更换具有权限的用户。"。
//如果是因为文件已经存在,导致失败,返回的Result,State为-2,ErrorMessage为"文件【C:\abc.txt】已经存在。如果需要覆盖,请添加参数:arg_overwrite = true"。
//如果是因为创建文件发生超时,导致失败,返回的Result,State为-3,ErrorMessage为"在创建文件时超时,请使用chkdsk检查文件系统是否存在问题。"。</span>


       4.我个人推崇上面这种方式,完整,美观。但是这种流程,容易与正常的代码混在一起,不好区分开。因此,Java、C#等设计了try catch这一种特殊的方式:
void CreateFile()
//如果创建成功就不会抛出异常。
//如果是因为没有权限,导致失败,会抛出AccessException,这个Exception的Msg属性为"用户【guest】没有权限在【C:\】这个目录下创建该文件。建议您向管理员申请权限,或者更换具有权限的用户。"。
//如果是因为文件已经存在,导致失败,会抛出FileExistedException,这个Exception的Msg属性为"文件【C:\abc.txt】已经存在。如果需要覆盖,请添加参数:arg_overwrite = true"。
//如果是因为创建文件发生超时,导致失败,会抛出TimeoutException,这个Exception的Msg属性为"在创建文件时超时,请使用chkdsk检查文件系统是否存在问题。"。

    可见,上述机制,实际上是用不同的Exception代替了【3】的State。

这种机制,在外层使用时:
try
{
....CreateFile( "C:\abc.txt" );
}
catch( AccessException e )
{
....//代码进入这里说明发生【没有权限错误】
}
catch( FileExistedException e )
{
....//代码进入这里说明发生【文件已经存在错误】
}
catch( TimeoutException e )
{
....//代码进入这里说明发生【超时错误】
}
对比一下【3】,其实这与【3】本质相同,只是写法不同而已。


5.综上,我个人喜欢【3】这类面向过程的写法。但很多喜欢面向对象的朋友,估计更喜欢【4】的写法。然而

【3】与【4】都一样。这两种机制都是优秀的错误处理机制。

6.理论说完了,回到正题,题注问:为什么不用try catch?

      解答:这是因为,有的人可能还不是很熟练,以及新手,他们可能这样写代码的:

<span style="font-size:18px;">void CreateFile( )
//无论遇到什么错误,就抛一个 Exception,并且也不给出Msg信息。
这样的话,在外层只能使用:
try
{
....CreateFile( "C:\abc.txt" );
}
catch( Exception e )
{
....//代码进入这里说明发生错误
}</span>


当出错后,只知道它出错了,并不知道是什么原因导致错误。这同【1】。

 以及,即使CreateFile是按【4】的规则设计的,但菜鸟在外层是这样使用的:
<span style="font-size:18px;">try
{
....CreateFile( "C:\abc.txt" );
}
catch( Exception e )
{
....//代码进入这里说明发生错误
....throw Exception( "发生错误" )
}</span>


   这种情况下,调用了这段代码,或者用户看到这个错误信息,也只能知道发生了错误,但并不清楚错误的原因。这

与【1】是相同的。

    出于这些原因,可能新手以及用户,并没有想到,造成这个问题原因是熟练度不够,写代码图简单省事。他们却以 

为是try catch机制不行。

     所以,在这种情况下,肯定很多人觉得,还是不建议用try catch。


二 、经验总结:

        最好问清楚是那种语言。不同语言处理Try Catch的机制不一样,所以也会有不同回答。

 (1)对于C++:

        是不推荐用try catch的,它推荐使用Windows API那种HResult来返回错误情况,原因是try catch会在已有的代码

上面增加额外的cost, 这个额外的cost不是说只有throw exception的时候才会有,而是在try catch block里面的每一行

代码中都会有,这也是为什么他不建议你使用try catch最主要的原因。在Windows的源代码中,是没有任何try catch

的,全部用HResult来处理。

  (2)对于C#:

         try catch是建议使用的,C#设计的时候吸取的C++ try catch的教训,所以直接用Try catch包裹已有代码增加的

cost可以忽略不计,但是如果真的在代码运行过程中throw exception了,这个cost还是很大的。所以,在C#代码设计

中,throw exception基本上是你认为不会发生这种意外的情况下,否则,如果是常见错误,最好不要throw 

exception。

     比如Java, try catch也是建议使用的,我这个用的不熟,不过看它的说明,即使是throw exception的时候的cost也

很小。

三、在java语言中:

     其实通过上面的例子我们发现,不是不建议用.而是不应该滥用.

      这里《Effective Java》的有关异常的几个条目说的非常明白.建议题主去看一下.我这里就简单的搬运一下.部分原

文如下:

     只针对不正常的情况才使用异常书中给出了一个例子
try {
int i=0;
while (true) {
arr[i]=0;
i++;
}
} catch (IndexOutOfBoundsException e) {
}


  这是一个非常明显的错误,希望通过异常来中断循环而达到某种优化.其实不然.
  

     •JVM对异常的块中的代码几乎不做优化.

  

     •而且创建、抛出、捕获异常都是十分昂贵的

    •正常的遍历数组并不会造成冗余的边界检查,现代的JVM会做出优化

    避免不必要的使用被检查的异常

       “被检查的异常”是Java语言的一个很好的特性。与返回代码不同,"被检查的异常"会强迫程序员处理例外的条

件,大大提高了程序的可靠性。

 

        但是,过分使用被检查异常会使API用起来非常不方便。如果一个方法抛出一个或多个被检查的异常,那么调用

该方法的代码则必须在一个或多个catch语句块中处理这些异常,或者必须通过throws声明抛出这些异常。 无论是通

过catch处理,还是通过throws声明抛出,都给程序员添加了不可忽略的负担。

      适用于"被检查的异常"必须同时满足两个条件:第一,即使正确使用API并不能阻止异常条件的发生。第二,一旦

产生了异常,使用API的程序员可以采取有用的动作对程序进行处理。

   不要忽略异常,有些程序员会写出下面的代码
<span style="font-size:24px;">try {
...
} catch (SomeException e) {
}
</span>


  空的catch块会使异常达不到应有的目的,异常的目的是强迫你处理不正常的条件。忽略一个异常,就如同忽略一

个火警信号一样 -- 若把火警信号器关闭了,那么当真正的火灾发生时,就没有人看到火警信号了。所以,至少catch

块应该包含一条说明,用来解释为什么忽略这个异常是合适的。

  小结:

       try catch是否建议使用要看具体语言,最重要衡量的标准就是它对已有的代码性能有多大的影响。但是
从它设计的角度就是为了处理一些意料不到的情况,但是因为当初引入的时候各种各样的原因,导致有些语言为了性
能,不推荐使用。
      
         BTW, try catch最好不要catch (Exception), 这样会吃掉不该吃的问题,比如C#中的StackOverflowException, 
OutOfMemoryException, NullReferenceException etc. 该crash的时候就应该让App crash, restart, 这也是保护你
service的一个好方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: