异常处理
1.1 什么是异常
异常是指在程序中导致程序中断的一种指令
1.2 try catch 处理异常
伪代码如下:
try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){
// 异常的处理操作
}
finally{
// 异常的统一出口
}
1.2.1 try catch 的处理流程
- 一旦产生异常,系统就会自动产生一个异常类的实例化对象
- 那么,此时如果异常发生在try语句,则会自动找到匹配的catch语句执行,如果没有在try语句中,则会将异常抛出
- 所有的catch根据方法的参数匹配异常类的实例化对象,如果匹配成功则表示由此catch块进行处理
- 处理流程:
- 发生异常(JVM根据异常的情况,创建一个异常对象 - 包含了异常信息)
- main未处理,自动将异常抛给了main的调用者JVM
- JVM对异常信息进行了响应(将异常信息显示到控制台,终端处理)
1.2.2 finally
在进行异常的处理之后,在异常的处理格式中还有一个finally语句,那么此语句将作为异常的统一出口,不管是否产生 了异常,最终都要执行此段代码
1.3 异常体系结构
异常指的是Exception,Exception类,在Java中存在一个父类Throwable(可能的抛出)
Throwable 存在两个子类:
- Error:表示的是错误,是JVM发出的错误操作,只能尽量避免,无法用代码处理
- Exception:一般表示所有程序中的错误,所以一般在程序中将进行try…catch的处理。
1.4 异常捕获注意点
-
捕获更粗的异常不能放在捕获更细的异常之前
-
如果为了方便,则可以将所有的异常都使用Exception进行捕获
-
多异常捕获
catch(异常类型1 |异常类型2 对象名){ //表示此块用于处理异常类型1 和 异常类型2 的异常信息 }
1.5 Throw 关键字
-
throw关键字主要在方法的声明上使用,表示方法中不处理异常,而交给调用处处理
-
throw关键字表示在程序中人为的抛出一个异常,因为从异常处理机制来看,所有的异常一旦产生之后,实际上抛出 的就是一个异常类的实例化对象,那么此对象也可以由throw直接抛出
throw new Exception("异常");
1.6 RuntimeExcepion与Exception的区别
只要是RuntimeException的子类,则表示程序在操作的时候可以不必使用try catch进行处理,如果有异常发生,则由JVM进行处理。当然,也可以通过try catch处理。
1.7 自定义异常类
编写一个继承Exception的子类,并重写一参数的构造方法,即可完成自定义受检异常类
编写一个继承RuntimeException的子类,并重写一参数的构造方法,即可完成自定义运行时异常类型
class MyException extends Exception {
public MyException(String msg) {
super(msg);//调用Exception中有一个参数的构造方法
//TODO: 做其他处理
}
}
1.8 异常处理面试
-
try-catch-finally 中哪个部分可以省略?
catch和finally可以省略其中之一,但不能同时省略
一般不会省略catch
-
try-catch-finally中,如果 catch中 return 了,finally 还会执行吗?
finally中的代码会执行
执行流程:
-
先计算返回值,并将返回值存储起来,等待返回
-
执行finally代码块
-
将之前存储的返回值,返回出去
/** * 基本数据类型会将副本保存,直接保存副本 * 引用数据类型会保存引用,也就是地址,在返回时会被修改 */ public class Test { public static void main(String[] args) { System.out.println(getNum()); System.out.println(getBook().name); } // 此方法返回20 public static int getNum() { int a = 20;// 基本数据类型 try { return a; } catch (Exception e) { return 0; } finally { a = 10; } } // 此方法返回“水浒传” public static Book getBook() { Book b = new Book(); try { b.name = "西游记"; return b; } catch (Exception e) { return null; } finally { b.name = "水浒传"; } } static class Book { String name; } }
注:基本数据类新在栈内存中直接存储值
注意:
- 返回值是在finally运算之前就确定,并且缓存,不管finally对该值做任何的改变,返回的值都不会改变
- finally代码中不建议包含 return,因为程序会在上述的流程中提前退出,也就是说返回的值不是 try 或 catch 中的值
- 如果在try或catch中停止了JVM,则 finally 不会执行。例如停电- -,或通过如下代码退出 JVM:System.exit(0);
-
1.9 常见异常
1.9.1Java中非检查异常
异常 | 描述 |
---|---|
ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在需要对象的地方使用 null时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
1.9.2 Java中检查性异常
异常 | 描述 |
---|---|
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
NoSuchFieldException | 请求的变量不存在 |
1.9.3 异常方法
序号 | 方法以及说明 |
---|---|
1 | public String getMessage() 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 |
2 | public Throwable getCause() 返回一个Throwable 对象代表异常原因。 |
3 | public String toString() 使用getMessage()的结果返回类的串级名字。 |
4 | public void printStackTrace() 打印toString()结果和栈层次到System.err,即错误输出流。 |
5 | public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 |
6 | public Throwable fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 |