博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java异常拾遗
阅读量:2231 次
发布时间:2019-05-09

本文共 6491 字,大约阅读时间需要 21 分钟。

概述

当方法内部发生一项错误时,该方法会创建一个对象传递给运行时系统(runtime system),这个对象被称为异常对象,包括错误的类型、发生位置。程序状态等一系列信息。

当一个方法抛出异常时,运行时系统会沿着调用栈(call stack)寻找该异常的处理方式 。

下图中,调用栈以下的方法调用了上面的方法,层层嵌套,一共四层:

调用第三个方法时抛出了一个异常,运行时系统就会沿着调用栈反向寻找该异常的处理程序,当该异常类型与某个异常处理程序声明的异常类型一致时。系统就将该异常交给它处理。

假设系统没能找到合适的异常处理程序,系统将会终止。

 

异常类型

java提供了两种处理异常的方式:

(1)   使用try语句捕获异常并处理。

(2)   使用throwskeyword列出要抛出的异常类型,代表在本方法内不做处理。可是调用该方法的方法必须处理该异常或者继续抛出。

 

并非全部异常都须要显式处理(这里的处理代表在程序内部捕获或者抛出),比方IOException、SQLException等是必须要处理的。而NullPointerException、ArithmeticException、IndexOutOfBoundsException等能够不作处理。

理解这一点。就要弄清异常的基本分类。

Checked Exception

这类异常是应用程序能够预见并能够恢复的错误。比方。应用程序须要用户输入一个文件名称,然后程序将对这个文件进行读写操作。假如用户输入的文件名称不存在。抛出java.io.FileNotFoundException,应用程序应该捕获这个异常并提醒用户。相似这样的异常就属于checked exception。

除了Error、RuntimeException以及两者的子类,全部异常都属于checked exception

Error

Error一般来说是应用程序外部引起的异常,应用程序通常不能预见并恢复。比方,程序顺利打开了一个文件,可是因为硬件或者操作系统故障,不能够读取文件里的内容,程序就会抛出java.io.IOError。

Runtime Exception

runtimeexception一般来说是程序内部引起的异常,应用程序通常能够预见并恢复。

这类异常的出现一般暗示程序存在bug。比方,还是文件操作的样例。因为逻辑错误,传入的文件名称为空值,程序就会抛出一个NullPointerException。

尽管能够让程序捕获runtimeexception,但更合适的做法是剔除引起这类异常的bug。

 

java的异常类层次图例如以下:

异常的捕获

checked exception必须捕获。而unchecked exception的捕获不是必须的比如:

import java.io.*;import java.util.List;import java.util.ArrayList; public class ListOfNumbers {     private List
list; private static final int SIZE = 10; public ListOfNumbers () { list = new ArrayList
(SIZE); for (int i = 0; i < SIZE; i++) { list.add(new Integer(i)); } } public void writeList() { try{ // FileWriter的构造方法 throws IOException, checked exception类型,必须捕获 PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt")); for (int i = 0; i < SIZE; i++) { // get(int)方法throws IndexOutOfBoundsException,RuntimeException的子类。unchecked exception类型,不是必须要捕获的 out.println("Value at: "+ i + " = " + list.get(i)); } out.close(); }catch(IOException e){ //捕获IOException ... } }}
unchecked exception在一些特殊的情况下也能够选择捕获它,比方上面的程序,如今既要捕获IOException,也要捕获IndexOutOfBoundsException。改写例如以下:

public void writeList() {         try{         // FileWriter的构造方法 throws IOException, checked exception类型。必须捕获        PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));         for (int i = 0; i < SIZE; i++) {            // get(int)方法throws IndexOutOfBoundsException。RuntimeException的子类。unchecked exception类型,不是必须要捕获的            out.println("Value at: "+ i + " = " + list.get(i));        }        out.close();         }catch(IndexOutOfBoundsException e){  //捕获IndexOutOfBoundsException                ...         }catch(IOException e){  //捕获IOException                ...         }

 

假设要同一时候捕获的异常存在继承关系,即某个异常时还有一个异常的子类,必须把父类异常写在子类异常后面,否则会报编译错误。

可是。不管有几个捕获语句,终于至多会进入一个catch语句。

比如:

public class Example {           public void test() throws IOException{             throw new IOException();      }           public static void main(String args []){                         Example example  = new Example();                         try {                    example.test();             } catch (IOException e) {                    System.out.println("捕获了子类异常");             } catch (Exception e) {                    System.out.println("捕获了父类异常");             }                  }     }

上例中,IOException是Exception的子类,假设方法抛出了IOException异常,会进入第一个catch子句,但不会进入第二个catch语句;假设抛出的是非IOException的其它Exception子类异常。则会直接进入第二个catch子句。

也就是说,不会同一时候进入两个catch子句

从Java SE 7以后,一个catch块能够捕获多个异常。上面的捕获语句可简写为:

catch (IndexOutOfBoundsException | IOException ex) {    ...}
须要注意的是,这样的情况下,catch的參数(上例中的“ex”)默认是final的。不能够在catch块中对它再次赋值。

 

不管异常是否发生,try代码块退出后,finally代码块都会运行。经常常使用于释放资源。比如:

  

public void writeList() {       PrintWriter out = null;    try{      out = new PrintWriter(new FileWriter("OutFile.txt"));       for (int i = 0; i < SIZE; i++) {          out.println("Value at: " +i + " = " + list.get(i));      }         }catch(IOException e){            ...    }finally{  //释放资源             if(out!=null){                    out.close();             }    }  }

上例中,有三种情况可导致try代码块退出:

(1)newFileWriter("OutFile.txt")抛出IOException

(2)list.get(i)抛出IndexOutOfBoundsException

(3)无异常抛出,代码运行完成

不管发生了上面的那种情况,运行时系统都会保证finally代码块中的程序运行。

须要注意的是,假设在运行try-catch代码块的时候JVM退出了。或者运行try-catch代码块的线程被中断或者杀死。或者使用了System.exit()函数等。finally代码块有可能不被运行

 

带有返回值的函数中使用了try-catch-finally块,且返回值与是否发生异常有关,则应该避免将返回值写在finally块中,因为不管是否会发生异常,都会依照finally块的返回值。而忽略try-catch不论什么地方的返回值。比如:

public int test(){                         InputStream in = null;             try {                    File f = new File("F:\test.txt");                    in = new FileInputStream(f);                     return 1;              } catch (IOException e) {                    e.printStackTrace();                    return 2;             }finally{                    try {                           in.close();                    } catch (IOException e) {                           e.printStackTrace();                    }                    return 3;             }      }
上例中,不管是否会抛出IOException,都不会返回1或2,仅仅会返回3。

try-with-resources语句

在try中声明的一个或多个资源,在程序结束后应该关闭,通常我们是在finally代码块中完成这项工作。

 

从java 7開始。提供了一种更为简洁有效的写法: try-with-resources语句。

使用形式例如以下:

static String readFirstLineFromFile(String path) throws IOException {    try (BufferedReader br =                   new BufferedReader(new FileReader(path))) {        return br.readLine();    }}
try-with-resources确保{}内的程序运行完成后自己主动关闭资源,全部实现了java.lang.
AutoCloseable接口(java 7新增的接口,java.lang.Closeable的父接口。)的对象都能够当作资源。

throw与throws

捕获异常的前提是有方法抛出了异常。

throwkeyword用于在方法体内部,错误发生的地方抛出异常。如:

public Object pop() {    Object obj;     if (size == 0) {  //栈为空,抛出异常        throw new EmptyStackException();    }     obj = objectAt(size - 1);    setObjectAt(size - 1, null);    size--;    return obj;}
该方法用于从栈中弹出栈顶元素。可是。假设栈为空就不能进行这项操作。所以就会抛出EmptyStackException异常。

 

当其它方法调用pop()方法时。就应该考虑到pop()可能会抛出的异常,假设假设pop()抛出的UncheckedException,能够不做额外的处理;假设pop()抛出的是checked Exception则必须进行处理,能够用try-catch捕获,也能够选择在本方法内不做捕获,继续用throwskeyword抛出。如:

public void callPop() throws EmptyStackException {      ...      pop(); //该方法可能会抛出EmptyStackException      ...}
 

实际上,一个异常非常多时候是因为还有一个cause异常引起的。因为cause 自身也会有 cause。依此类推,就形成了链式异常(Chained Exceptions)

比如:

try {

 

} catch(IOException e) {  //捕获到IOException时,抛出还有一个异常

   throw new SampleException("Other IOException", e);

}

Throwable有一种造函数能够接受Throwable类型的參数作为引起该异常的cause,Throwable类的initCause(Throwable)、getCause()能够设置cause信息、获取cause信息。

转载于:https://www.cnblogs.com/ljbguanli/p/7113018.html

你可能感兴趣的文章
【NLP学习笔记】(二)gensim使用之Topics and Transformations
查看>>
【深度学习】LSTM的架构及公式
查看>>
【python】re模块常用方法
查看>>
剑指offer 19.二叉树的镜像
查看>>
剑指offer 20.顺时针打印矩阵
查看>>
剑指offer 21.包含min函数的栈
查看>>
剑指offer 23.从上往下打印二叉树
查看>>
剑指offer 25.二叉树中和为某一值的路径
查看>>
剑指offer 60. 不用加减乘除做加法
查看>>
Leetcode C++《热题 Hot 100-14》283.移动零
查看>>
Leetcode C++《热题 Hot 100-15》437.路径总和III
查看>>
Leetcode C++《热题 Hot 100-17》461.汉明距离
查看>>
Leetcode C++《热题 Hot 100-18》538.把二叉搜索树转换为累加树
查看>>
Leetcode C++《热题 Hot 100-21》581.最短无序连续子数组
查看>>
Leetcode C++《热题 Hot 100-22》2.两数相加
查看>>
Leetcode C++《热题 Hot 100-23》3.无重复字符的最长子串
查看>>
Leetcode C++《热题 Hot 100-24》5.最长回文子串
查看>>
Leetcode C++《热题 Hot 100-28》19.删除链表的倒数第N个节点
查看>>
Leetcode C++《热题 Hot 100-29》22.括号生成
查看>>
Leetcode C++《热题 Hot 100-47》236.二叉树的最近公共祖先
查看>>