Java异常处理机制

Java中的异常类都派生自Throwable类,所以发生异常时将产生一个异常对象并将其抛出。这与其他对象的创建一样,使用new在堆上创建异常对象。然后,当前的执行路径被迫终止,并且从当前执行环境弹出异常对象的引用,这时异常处理机制开始运作,他会寻找一个恰当的地方继续执行程序(当前环境或者上一层环境中定义了异常处理的语句,如果没有我们定义相应的异常处理语句,那么抛出的异常会直达main()方法,并且输出异常调用栈轨迹printStackTrace(),然而这样就会终止整个程序),当异常对象在当前执行路径或者上一层环境中被异常处理语句捕获时,它将在其中接受处理,并在处理完成恢复程序的后续执行

 

异常抛出

我们可以在方法里使用throw关键字抛出异常对象,也可以在方法签名后通过throws关键字抛出一个异常类(异常说明)。

    public void findFile(File file)throws IOException{
        if(file == null)
            throw new IOException();
    }

在这段代码中,我们在file等于null时抛出一个IO异常对象,这时编译器会提醒我们在这个方法块中编写处理这个异常的异常处理机制,我们可以通过在方法签名后面抛出这个类型的异常来将异常处理延迟到上一层环境中处理。

那什么是上一层环境呢?在下面的捕获异常中会给出解释。

 

捕获异常

    public void findFile(File file)throws IOException{
        if(file == null)
            throw new IOException();
    }
    
    public void fun(File file){
        /*
        * try-catch块
        * 包裹在try中的监控区域将检测抛出的异常
        * */
        try {
          /*
          *调用抛出异常的方法findFile(File file);
          */
            findFile(file);
        } catch (IOException e) {
            /*
            * 发生错误后干的事情
            * */
            e.printStackTrace();
        }
    }

Java中采用try-catch块捕获并处理异常,在这段代码中,定义了一个fun()成员方法,我们在其中调用了findFile()方法,此时相对于findFile()方法来说fun()方法的作用域就是上一层执行环境。可以在这时使用try-catch块捕获并处理异常,也可以在fun()方法签名后抛出异常类型待更上一层环境来处理。

catch语句中定义了可捕获异常的一个引用,当捕获到异常时,该引用将指向它。

 

受查异常和不查检异常

Java规范将派生于Error类或RuntimeException类的所有异常称为非受查异常,所有其他异常称为受查异常。因为编译器会核查是否为所有的受查异常提供了异常处理器。 

    public void findFile(File file){
        if(file == null)
            throw new RuntimeException();
    }

当我们在findFile()方法里抛出不受查异常时,我们可以不对它进行任何处理,当发生异常时它会直接终止程序执行并且在控制台输出异常调用栈信息。当然我们也可以将它包裹进可捕获相应不受查异常的try-catch块中去处理。

 

自定义异常

编写自定义异常是非常简单的,当我们需要自己去定义异常时,必须继承已有的异常类,可以让编译器为你产生默认的构造器。也可以创建有参的构造器以输出异常信息。 

import java.io.*;

/*
* 定义自定义异常类
* */
class FileNotFoundException extends IOException{

    /*
    * 可以调用父类的构造器编辑特定的异常信息
    * Message
    * */
    public FileNotFoundException(String Message) {
        super(Message);
    }
}

class ExceptionTest {
    public void findFile(File file)throws FileNotFoundException{
        if(file == null)
            /*
            * 抛出自定义异常异常
            * */
            throw new FileNotFoundException("文件找不到");
    }

}
public class FuUse{
    public static void main(String[] args){
        try {
            File file =null;
            ExceptionTest exceptionTest = new ExceptionTest();
            exceptionTest.findFile(file);
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }
    }
}
/*
* output:
* FileNotFoundException: 文件找不到
*   at ExceptionTest.findFile(FuUse.java:23)
*   at FuUse.main(FuUse.java:32)
* */

可以看到,在Java中对于异常来说,最重要的信息其实就是异常类名,通过异常类名我们就可以知道这个异常发生的原由。

 

finally块

有时候我们在处理异常时,并不能保证将被异常终止执行的那块代码或整个程序都关闭了所使用的资源。

import java.io.*;
public class FuUse{
    public static void main(String[] args){
        try {

            File file = new File("1231.txt");
            /*
            * 创建一个字节文件流
            * 这里将抛出文件无法找到的异常
            * */
            FileInputStream f = new FileInputStream(file);

            System.out.println("start_close");
            f.close();
            System.out.println("end_close");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/*
* output:
*java.io.FileNotFoundException: 1231.txt (系统找不到指定的文件。)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:196)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:139)
	at FuUse.main(FuUse.java:13)
* */

可以看出程序被异常中断时,并没有执行close()语句,这将导致流没有被关闭造成资源浪费。这时我们可以将所需要关闭的资源或其他必须执行的语句放入finally块中,不管有没有异常被捕获它都会执行里面的语句。

   try {
            file= new File("1231.txt");
            f = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            System.out.println("start_close");
            System.out.println("end_close");
        }
/*
* output:
*start_close
end_close
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:196)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:139)
	at FuUse.main(FuUse.java:8)
* */

 

posted @ 2018-12-10 19:15  问月晚安  阅读(166)  评论(0编辑  收藏  举报