ITOO技术攻坚过程中小编负责“代码优化”,其中一个亮点就是“异常处理”,在此通过博客形式分享给网友朋友们互相学习。 ---前言
异常处理过程中,最为常用的就是大家经常看到的try、 catch、 finall结构体的使用,这篇文章就对于try catch 体系中的5个关键字进行详细介绍。
try { // X } catch (Exception ex) { // Y } finally { // Z }
try-catch体系理解:
try(尝试)执行 X 这一段代码(认为X代码段是一段容易出现错误的代码段)。如果没有错误,那很好;如果 catch(捕捉)到错误了,那么执行 Y 这段代码。无论有没有错误,finally(最终)都执行 Z 这段代码。
贴一个在MSDN官网中查到的小例子帮助理解:class ExceptionTest { static double SafeDivision(double x, double y) { if (y == 0) throw new System.DivideByZeroException(); return x / y; } static void Main() { // Input for test purposes. Change the values to see // exception handling behavior. double a = 98, b = 0; double result = 0; try { result = SafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } catch (DivideByZeroException e) { Console.WriteLine("Attempted divide by zero."); } } }
Addition:对于Catch括号中捕获的异常类型,将在我接下来关于“异常处理”的博客中说明(这里水比较深),对于try catch finally先有一个简单的认识。
Maybe读者很奇怪为什么我引用MSDN中这个例子里面没有”finally”呢?那就对他们之间的组合关系来梳理一下吧:
try关键字用来包围可能会出现异常的逻辑代码,它单独无法使用,必须配合catch或者finally使用。他们之间的匹配方式有如下三种:
(1)try...catch...;
(2)try....finally......;
(3)try....catch...finally...
当然catch块可以有多个,注意try块只能有一个,finally块是可选的(但是最多只能有一个finally块)。
三个块执行的顺序为try—>catch—>finally。
至此,try catch 基本体系简单介绍完毕。
Try catch体系已经熟悉之后,对于”try”,只要包住可以引发异常的代码段即可(哪些代码属于容易引发异常?思考中……),先来对于”Catch”来思考一番:
顾名思义,Catch是“捕获”的意思,也就是说在这里要将异常进行捕获,对于Catch的使用一些细节进行总结:
(1)通过断点调试发现,try代码段中没有错误,不会执行catch中的代码。
(2)在捕获了异常之后什么都不做,相当于忽略了这个异常。千万不要使用空的catch块,空的catch块意味着你在程序中隐藏了错误和异常,并且很可能导致程序出现不可控的执行结果。---从大牛的博客中看到的一点,想想确实是,把异常捕获了,然后不处理,是不是有点徇私枉法的feeling呢?
从网上看一个小小的故事:
关于catch操作,永远记住,如果你不知道如何处理这个异常,你就让他抛出,让调用你的人去处理。假设A方法调用B方法,好比A是B的领导,指派B去干活,工作中出了纰漏,哪怕不是B的责任(比如B又调用了C,C出错了),如果B没这个权限的话,他就该把问题上报给他的领导,而不是私自把这个问题掩盖掉(catch且并不再throw出去)。
其实Catch之后不进行处理也是这个道理,就像是把异常藏起来一样一样的。
(3)catch块的顺序问题
在一个try—catch体系当中,一个try是可以对应多个catch的,就像我们在J2SE中学习到的异常类型:
对于不同类型的异常需要进行不同的捕获手段,就像是交警、武警、公安都是“警察”,但是他们抓的“坏人”确实不同的。
看代码:
<pre code_snippet_id="1607501" snippet_file_name="blog_20160312_3_4693988" name="code" class="java" style="font-family: 宋体; font-size: 10.5pt;">public class Main { public static void main(String[] args) { //调用打开文件的方法 String str = new Main().openFile(); System.out.println(str); } public String openFile() { try { FileInputStream inputStream = new FileInputStream("d:/zzh.txt"); int ch = inputStream.read(); System.out.println("zzh"); return "step1"; }catch (FileNotFoundException e) { System.out.println("file not found"); return "step2"; }catch (IOException e){
System.out.println("IO Exception");
return "step3";
<span style="font-size: 10.5pt;"> }</span><span style="font-size: 10.5pt;">finally{</span>
System.out.println("finally block"); //return "finally";
//在finally后不能写return,会将异常信息覆盖掉 } } }
一个小例子,打开D盘根目录下的”zzh.txt”文件,catch块有两个:1、FileNotFoundException 2、IOException,其中 FileNotFoundException是IOException的子类。
我们在两个Catch块使用过程中,一定要把级别高的catch放到后面,就像例子当中,我在D盘没有”zzh.txt”文件,首先会被FileNotFoundException捕获,进而到finally块中执行,如果把IOException放到首位,由它将异常捕获后直接进入finally中,对于异常信息的提示就不会特别清楚,因为IOException这个异常的范围太广了,所提示的信息就不明确。
(1)Throws:出现在方法的声明中,表示该方法可能会抛出的异常,然后交给上层调用它的方法程序处理,允许throws后面跟着多个异常类型。
Class A{ Public void method() throws IOException{} }
(2)Throw:出现在方法体中,当方法在执行过程中遇到异常情况时,将异常信息封装为异常对象,然后throw出去。
我的理解:在try catch体系中,catch捕获到异常之后,要么自己处理掉,要么抛给调用该方法的上一级去处理,而throw就是实现这一过程的代码段。
对比:Throws用于声明方法可能会抛出什么类型的异常,Throw则是真正的往出抛,一个“s”的差别,就是这样,理解很简单。
对于throw这块,由于代码接触的不是很充分,还不够系统,简单的理解之后,以后的博客将会更详细的从理论和实践两条线来分享我对于“异常处理”的学习成果。
上一篇异常处理:代码健壮性理论篇
下一篇异常处理:.Net中异常处理的最佳实践(转)