二、异常的处理                                                   
    Java提供了一种异常处理模型,它使您能检查异常并进行相应的处理。它实现的是异常处理的抓抛模型。使用此模型,您只需要注意有必要加以处理的异常情况。Java提供的这种异常处理模型,代替了用返回值或参数机制从方法返回异常码的手段。
异常处理的抓抛方法有两大优点:
1):异常情况能仅在有必要之处加以处理,而不在其发生处和需要进行处理处之间的每一级上均进行处理;
2):能够编写统一的、可重用的异常处理代码。
    应该区别对待程序中的正常控制流和异常处理流。当然,异常处理流也是程序中的控制流。当异常发生时,抛出一个异常。异常伴随调用链,直到它们被捕获或程序退出为止。
下面是Java语言中的异常处理块的模型:
try{
//放置可能出现异常的语句序列,一旦发生异常,马上转入catch语句的匹配
}catch(Exception1 el){
  //如果try块抛出异常对象的类型为Exceptionl,那么就在这里进行处理
}catch(Exception2 e2){
  //如果try块抛出异常对象的类型为Exception2,那么就在这里进行处理
}catch(ExceptionN eN){
   //如果try块抛出异常对象的类型为ExceptionN,那么就在这里进行处理
}finally{
 //不管是否有异常发生,始终执行这个代码块
}
在未提供适当异常处理机制的程序中,无论何时发生异常,程序均会异常中断,而之前分配的所有资源则保持其状态不变。这会导致资源遗漏。要避免这一情况,在适当的异常处理机制中,我们可以将以前由系统分配的所有资源返还给系统。所以,当异常可能发生时,要牢记必须对每一异常分别进行处理。
例如我们处理文件I/O,在打开文件时发生IOException,程序异常中断而没有机会关闭该文件,这可能会毁坏文件而且分配给该文件的操作系统资源可能未返还给系统。
1try                                                                              
try块由一组可执行语句组成,在执行它们时可能会抛出异常。try块后可随一个或多个catch块,用来捕获在try中抛出的异常。另一方面,try不可以跟随在catch块之后。
也就是说:try语句块中包含可能会产生异常的语句
int demo=0
try{
  System.out.println(20/demo);
}
语句 System.out.println(20/demo);
会抛出一个异常,原因是试图用0去除一个数。程序会被成功编译,但当运行该程序时,程序将会发生异常而中断,异常可在catch块中被捕获,try块可以嵌套:
try{
语句 1;
语句 2;
try{
语句3;
语句4;
}catch(Exception1 e){
    //异常处理
}
}catch(Exception2 e){
   //异常处理
}
   try块嵌套时,首先执行内部的try块,该块中引发的任何异常在随后的catch中被捕获;如果未发现与该内部块匹配的catch块,则检查外部try块的catch;如果发现匹配的catch块,那么在该块中处理这一异常,否则Java运行时环境(JRE)处理这一异常。
 
2catch                                                                            
catch块,从其名称就可以看出,是用来捕获并处理try中抛出的异常的代码块。没有try块,catch块不能单独存在,我们可有多个catch,以捕获不同类型的异常。下面是catch块的语法
try{
    }catch(异常类型  e){
    }
这里,e是异常类型类的对象的引用,利用这一对象,我们可以输出这一异常的详细信息
下面是catch/try块的一个简单示例:
class TryClass{
    public static void main(String args[]) {
      int demO=0
try{
        System.out.println(20/demO);
    }catch(ArithmeticException a){
        System.out.println(“Can not divided by zero”);
    }
  }
}
    上述程序的输出结果是:Can not devided by zero
注意:当多个catch块存在的时候,从上往下catch异常的范围应该从小到大,因为catch块的运行机制是找到一个匹配的就进行处理了,如果把范围大的放在前面,那么后面的代码就没有机会运行了,这会是一个编译异常,示例如下:
比如下面这个是正确的:
public  class Test {
    public static void main(String[] args) {
       try{
           int i = 5/0;
       }catch(ArithmeticException  e){
           e.printStackTrace();
       }catch(Exception err){
           err.printStackTrace();
       }     
    }
}
而下面这个就是错误的了,编译都发生了错误:
public  class Test {
    public static void main(String[] args) {
       try{
           int i = 5/0;
       }catch(Exception err){
           err.printStackTrace();
       }catch(ArithmeticException  e){
           e.printStackTrace();
       }     
    }
}
 
3finally                                                                        
finally块表示:无论是否出现异常,都会运行的块
通常在finally块中可以编写资源返还给系统的语句,通常,这些语句包括但不限于:
   1) 释放动态分配的内存块:
   2) 关闭文件;
   3) 关闭数据库结果集;
4) 关闭与数据库建立的连接;
它紧跟着最后一个块,是可选的,不论是否抛出异常,finally块总会被执行。
finally块的语法如下:
try{
}catch(异常类型1  e){
}catch(异常类型2  e){
}finally{
}
下面的程序显示的是finally块的使用
public class Test {
    static String name;
    static int n01, n02;
    public static void main(String args[]) {
       try {
           name = "Aptech Limited";
           n01 = Integer.parseInt(args[0]);
           n02 = Integer.parseInt(args[1]);
           System.out.println(name);
           System.out.println("Division is" + n01 / n02);
       } catch(ArithmeticException i) {
           System.out.println("Can not be divided by zero!");
       } finally {
           name = null;
           System.out.println("finally executed");
       }
    }
}
您从下面的命令行执行此程序:
Java Test 20 0
将会得到下面的输出:
Aptech Limited
Can not be divided by zero!
finally executed
 
现在从下面的命令行执行此程序:
Java Test 20 4
则会得到下面这样的输出:
Aptech Limited
Division is 5
finally executed
 
说明:当您用不同的命令行参数执行此程序时,均会看见“finally executed”的输出这意味着,无论try块是否抛出异常,都会执行finally块。
 
4trycatchfinally块的关系                                                    
1 try块不能单独存在,后面必须跟catch块或者finally
2 三者之间的组合为:trycatch trycatchfinally  tryfinally 这几种是合法的
3 一个try块可以有多个catch块,从上到下多个catch块的范围为从小到大
 
5throw语句                                                                    
throw语句用来从代码中主动抛出异常。throw的操作数是任一种异常类对象,主要用于后面介绍的产生自定义异常的对象。
下面是throw关键字的一个语法示例:
try {
    int i = 5/0;
} catch (ArithmeticException i) {
    throw new Exception("Can not be divided by zero!");
}
 
6throws语句                                                                   
throws用来在方法定义时声明异常。
Java中对异常的处理有两种方法,一个就是try-catch,然后自己处理;一个就是不做处理,向外throws,由别人去处理。
Java语言要求在方法定义中列出该方法抛出的异常:
public Class Example
{
    public static void exceptionExample() throws ExampleExceptionLookupException
{
}
}
在上面的示例中,exceptionExample()声明包括throws关键字,其后列出了此方法可能抛出的异常列表。在此案例中列出的是ExampleExceptionLookupException
比如前面那个例子写完整如下:
public class Test {
    public static void main(String args[])throws Exception {
       try {
           int i = 5/0;
       } catch (ArithmeticException i) {
           throw new Exception("Can not be divided by zero!");
       }
    }
}
 
7.调用栈机制                                                                               
如果方法中的一个语句抛出一个没有在相应的try/catch块中处理的异常,那么这个异常就被抛出到调用方法中。如果异常也没有在调用方法中被处理,它就被抛出到该方法的调用程序。这个过程要一直延续到异常被处理。如果异常到这时还没被处理,它便回到main(),而且,即使main()不处理它,那么,该异常就异常地中断程序。
考虑这样一种情况,在该情况中main()方法调用另一个方法(比如,first()),然后它调用另一个(比如,second())。如果在second()中发生异常,那么必须做一个检查来看看该异常是否有一个catch;如果没有,那么对调用栈(first())中的下一个方法进行检查,然后检查下一个(main())。如果这个异常在该调用栈上没有被最后一个方法处理,那么就会发生一个运行时错误,程序终止执行。
8.处理或声明规则                                                                          
为了写出健壮的代码,Java编程语言要求,当一个方法在栈(即,它已经被调用)上发生Exception(它与ErrorRuntimeException不同)时,那么,该方法必须决定如果出现问题该采取什么措施。
程序员可以做满足该要求的两件事:
第一,   通过将try{}catch(){}块纳入其代码中,在这里捕获给被命名为属于某个父类的异常,并调用方法处理它。即使catch块是空的,这也算是处理情况。
第二,   让被调用的方法表示它将不处理异常,而且该异常将被抛回到它所遇到的调用方法中。按如下所示通过用throws子句标记的该调用方法的声明来实现的:
public void troublesome() throws IOException
    关键字throws之后是所有异常的列表,方法可以抛回到它的调用程序中。尽管这里只显示了一个异常,如果有成倍的可能的异常可以通过该方法被抛出,那么,可以使用逗号分开的列表。
是选择处理还是选择声明一个异常取决于是否给你自己或你的调用程序一个更合适的候选的办法来处理异常。