首页 > 代码库 > Java的异常处理

Java的异常处理

以下内容引用自http://wiki.jikexueyuan.com/project/java/exceptions.html:

异常是一个程序执行过程中出现的问题。引起异常的原因包括以下几点:

  • 用户输入无效的数据
  • 用户打开一个不能被找到的文件
  • 网络连接已经丢失或JVM已经耗尽内存

一些异常是由于用户的错误,也有是因为程序员的错误,还有是因为一些物理资源在某些形式上的错误。

在Java中了解异常处理,需要了解异常的三个类别:

  • 检测异常(Checked exceptions:一个已检测异常通常是用户错误或是一个程序员不能预见的错误,如果一个文件将要被打开,但系统找不到这个文件,异常就会发生。这些异常在编译时不能被简单忽略。
  • 运行时异常(Runtime Exceptions):运行时异常是可以被程序语法避免的。不同于检测异常,运行时异常在编译时可以被忽略。
  • 错误(Errors):这并不是异常,但这不是用户或程序员可以控制的。错误经常在代码中被忽略,因为针对一个错误几乎做不了任何事。比如,如果一个堆栈溢出发生时,将会出现一个错误。他们在编译时也会被忽略。

一、异常的层次结构

所有的异常类都是java.lang.Exception类的子类型。异常类都是Throwable类的子类。除了异常类Error类也是由Throwable类产生的的子类。

错误一般不会由Java程序解决。这些条件通常是在Java程序解决不了的错误出现时才会发生。 Errors用来去指示那些运行时环境生成的错误。举例说明:JVM(java虚拟机)是不在内存中的。一般程序不能从错误中恢复。

Exception类含有两个子类:IOException类和RuntimeException类。

技术分享

二、异常方法

下面是Throwable类的重要方法列表。

方法描述
public String getMessage() 返回关于发生异常的细节信息,这些信息在Throwable的构造函数中被初始化
public Throwable getCause() 返回发生异常的原因,由Throwable对象来表示
public String toString() 返回与getMessage()的结果相联系的类的名称
public void printStackTrace() 打印toString()跟踪错误输出流的栈地址的结果。
public StackTraceElement [] getStackTrace() 返回一个数组,其中包含每个元素在栈的地址。元素的索引0代表调用栈的顶部,最后一个元素表示方法调用栈的底部。
public Throwable fillInStackTrace() 用当前栈地址来填充Throwable对象的栈地址,添加到任何先前的栈地址信息。

三、捕获异常

一个方法用关键字try和catch来捕获异常。一个try/catch块放置在可能产生异常的代码外。在try/catch块内的代码是被保护的,并且其语法如下:

try{   //Protected code}catch(ExceptionName e1){   //Catch block}

关于catch的声明,必须要指明捕获的异常的类型。如果受保护的代码中发生异常,跟在try后面的catch块会被检测。如果异常类型在catch中出现了,那么这个异常会被传递到catch当中,就像实参传递到方法参数当中。

示例:

下面的例子声明了一个含有两个元素的数组。然后代码试图访问数组的第三个元素,这将抛出一个异常。

// File Name : ExcepTest.javaimport java.io.*;public class ExcepTest{   public static void main(String args[]){      try{         int a[] = new int[2];         System.out.println("Access element three :" + a[3]);      }catch(ArrayIndexOutOfBoundsException e){         System.out.println("Exception thrown  :" + e);      }      System.out.println("Out of the block");   }}//这将产生如下的结果Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3Out of the block

四、多个catch块

一个try块可以有多个catch块。多个catch块的语法如下:

try{   //Protected code}catch(ExceptionType1 e1){   //Catch block}catch(ExceptionType2 e2){   //Catch block}catch(ExceptionType3 e3){   //Catch block}

前面的语句演示三个catch块,但是可以在一个try后面跟任意数量的catch块。当被保护代码中出现异常时,异常首先会被第一个catch块抓住,如果该异常类型在第一个catch块中列出,便在第一个catch块中被捕获。如果没有列出,便依次向下一个catch块中去匹配,直到找到该异常类型。最后不论是否找到现有的方法都会停止执行,并且抛出异常到上一个方法的栈地址。

示例:

下面是代码段显示如何使用多个try/catch语句。

try{   file = new FileInputStream(fileName);   x = (byte) file.read();}catch(IOException i){   i.printStackTrace();   return -1;}catch(FileNotFoundException f) //Not valid!{   f.printStackTrace();   return -1;}

五、throws/throw关键词

如果一个方法不能处理检测异常,那么该方法必须用关键字throws来声明。throws关键字在方法名的最后出现。

可以通过关键字throw来抛出一个异常或进行刚捕获到的异常的实例化。

以下方法声明它抛出RemoteException异常:

import java.io.*;public class className{   public void deposit(double amount) throws RemoteException   {      // Method implementation      throw new RemoteException();   }   //Remainder of class definition}

一个方法可以声明抛出一个以上的异常,这些异常用逗号分隔。例如,下面的方法声明抛出RemoteException和InsufficientFundsException :

import java.io.*;public class className{   public void withdraw(double amount) throws RemoteException, InsufficientFundsException   {       // Method implementation   }   //Remainder of class definition}

提示:throw用于抛出异常,throws用于告诉调用此方法的方法需要处理这个异常,同样throws可以在调用的方法中不用处理,直接throws给上一层,知道给JVM去处理。

六、关键字finally

finally关键字用于创建跟在try后面的代码块,finally代码块总是会被执行的,不管是怎样的异常发生。

使用finally块允许运行想要执行的任何cleanup-type语句,无论在受保护的代码中发生什么。

finally代码块出现在最后一个catch块之后并且语法如下:

try{   //Protected code}catch(ExceptionType1 e1){   //Catch block}catch(ExceptionType2 e2){   //Catch block}catch(ExceptionType3 e3){   //Catch block}finally{   //The finally block always executes.}

示例:

public class ExcepTest{   public static void main(String args[]){      int a[] = new int[2];      try{         System.out.println("Access element three :" + a[3]);      }catch(ArrayIndexOutOfBoundsException e){         System.out.println("Exception thrown  :" + e);      }      finally{         a[0] = 6;         System.out.println("First element value: " +a[0]);         System.out.println("The finally statement is executed");      }   }}//这将产生如下结果:Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3First element value: 6The finally statement is executed

以下几点需要注意:

  • catch在没有try关键字的情况下是不能够出现的。
  • try/catch语句块中并不是强制出现finally块。
  • try语句块不能独立存在(即没有任何catch和finally块)。
  • 在try/catch和finally块之间是不能出现任何代码的。

七、声明自己的异常

可以在Java中创建自己的异常。编写自己的异常类,要记住以下几点:

  • 所有的异常必须Throwable的子类。
  • 如果想写一个自动遵守正确处理或声明规则的检测异常,需要继承Exception 类。
  • 如果想编写一个运行时异常,需要继承RuntimeException类。

如下可以定义自己的异常类:

class MyException extends Exception{}

只需要继承Exception类来创建自己的异常类。这些被认为是检测异常。以下InsufficientFundsException类是一个用户定义的异常,同样继承了Exception类,成为检测异常。一个异常类和任何其他类一样,包含字段和方法。

例子:

// File Name InsufficientFundsException.javaimport java.io.*;public class InsufficientFundsException extends Exception{   private double amount;   public InsufficientFundsException(double amount)   {      this.amount = amount;   }    public double getAmount()   {      return amount;   }}

为了演示使用用户定义的异常,下面的CheckingAccount类包含一个withdraw()方法抛出了一个InsufficientFundsException异常。

// File Name CheckingAccount.javaimport java.io.*;public class CheckingAccount{   private double balance;   private int number;   public CheckingAccount(int number)   {      this.number = number;   }   public void deposit(double amount)   {      balance += amount;   }   public void withdraw(double amount) throws InsufficientFundsException   {      if(amount <= balance)      {         balance -= amount;      }      else      {         double needs = amount - balance;         throw new InsufficientFundsException(needs);      }   }   public double getBalance()   {      return balance;   }   public int getNumber()   {      return number;   }}

下面的BankDemo程序演示了调用CheckingAccount的deposit()和withdraw()方法。

// File Name BankDemo.javapublic class BankDemo{   public static void main(String [] args)   {      CheckingAccount c = new CheckingAccount(101);      System.out.println("Depositing $500...");      c.deposit(500.00);      try      {         System.out.println("\nWithdrawing $100...");         c.withdraw(100.00);         System.out.println("\nWithdrawing $600...");         c.withdraw(600.00);      }catch(InsufficientFundsException e)      {         System.out.println("Sorry, but you are short $"                                  + e.getAmount());         e.printStackTrace();      }    }}

编译上述三个文件并运行 BankDemo,将产生以下结果:

Depositing $500...Withdrawing $100...Withdrawing $600...Sorry, but you are short $200.0InsufficientFundsException        at CheckingAccount.withdraw(CheckingAccount.java:25)        at BankDemo.main(BankDemo.java:13)

八、常见的异常

在Java中,可以定义两种异常和错误

  • JVM异常:这些异常/错误是由JVM在逻辑层上或专门抛出的。例如:NullPointerException,ArrayIndexOutOfBoundsException,ClassCastException。
  • 程序性异常:这些异常是由应用程序或是编写API的程序员明确抛出的,例如:IllegalArgumentException,IllegalStateException。

 

测试工程:https://github.com/easonjim/5_java_example/tree/master/javabasicstest/test15

Java的异常处理