文章目录
- 1.概念和结构体系
- 1.1概念
- 1.2结构体系
- 2.常见异常类型
- 2.1空指针异常
- 2.2数组越界异常
- 2.3算数异常
- 3.异常的分类
- 3.1编译时异常
- 3.2运行时异常
- 4.异常的处理
- 4.1防御式编程
- 4.2异常的抛出
- 4.3异常的捕获
- 4.3.1异常申明throws
- 4.3.2try-catch捕获并处理异常
- 4.3.3finally
- 4.4异常的处理流程
- 5.自定义异常
1.概念和结构体系
1.1概念
java中,将程序执行过程中发生的不正常行为称为异常,java中不同类型的异常,都有与其对应的类来进行描述
1.2结构体系
- Throwable:是异常体系的顶层类,其派生出两个的子类,Error 和 Exception
- Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表:StackOverflowError和OutOfMemoryError
- Exception:异常产生后程序员可以通过代码进行处理,使程序继续执行,我们平时所说的异常就是Exception
2.常见异常类型
2.1空指针异常
public class TextDame {
public static void main(String[] args) {
int[] array = null;
System.out.println(array.length);
}
}
2.2数组越界异常
public class TextDame {
public static void main(String[] args) {
int[] array = {1,2,3,4};
System.out.println(array[10]);
}
}
2.3算数异常
public class TextDame {
public static void main(String[] args) {
int a = 10 / 0;
System.out.println(a);
}
}
3.异常的分类
3.1编译时异常
在程序编译期间发生的异常,称为编译时异常,也称为受检查异常,ClassNotFoundException和CloneNotSupportedException以及IOException及其子类都是编译时异常
3.2运行时异常
在程序执行期间发生的异常,称为运行时异常,也称为非受检查异常,RunTimeException以及其子类对应的异常,都称为运行时异常
4.异常的处理
4.1防御式编程
(1)事前防御型:在操作之前就做充分的检查,使用大量的if else语句进行判断,缺点是正常流程和错误处理流程代码混在一起,代码整体显的比较混乱
(2)事后认错型:使用try catch语句,优点是正常流程和错误流程是分离开的, 程序员更关注正常流程,代码更清晰,容易理解代码,异常处理主要的5个关键字:throw、try、catch、final、throws
4.2异常的抛出
借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者
注意:
- throw必须写在方法体内部
- 抛出的对象必须是Exception 或者 Exception 的子类对象
- 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
- 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
- 异常一旦抛出,其后的代码就不会执行
public class TextDame {
public static void main(String[] args) {
int[] array = null;
try {
if (array == null){
throw new NullPointerException("空指针异常");
}
}catch (NullPointerException e){
System.out.println("捕获到空指针异常");
}
}
}
4.3异常的捕获
4.3.1异常申明throws
在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛给方法的调用者来处理
注意:
- throws必须跟在方法的参数列表之后
- 声明的异常必须是 Exception 或者 Exception 的子类
- 方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可
- 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出
class Person implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class TextDame {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
Person person1 = (Person) person.clone();
}
}
4.3.2try-catch捕获并处理异常
throws对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch
语法格式:
try{
// 存放可能出现异常的代码
}catch(要捕获的异常类型 e){
// 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型一致时,或者是try中抛出异常的父类时,就会被捕获到,对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码
}finally{
// 此处代码一定会被执行到
}
public class TextDame {
public static void main(String[] args) {
try {
int[] array = null;
System.out.println(array.length);
}catch (NullPointerException e){
System.out.println("捕获到空指针异常");
}
}
}
注意:
- try块内抛出异常位置之后的代码将不会被执行
- 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到JVM收到后中断程序,因为异常是按照类型来捕获的
public class TextDame {
public static void main(String[] args) {
try {
int[] array = null;
System.out.println(array.length);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("捕获到空指针异常");
}
}
}
- try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获,且前一个异常的类型范围必须小于等于后一个异常
- 可以通过一个catch捕获所有的异常,即多个异常,一次捕获,但是不推荐,因为可读性差且不知道捕捉到的到底是什么异常,catch 进行类型匹配的时候, 不光会匹配相同类型的异常对象,也会捕捉目标异常类型的子类对象
4.3.3finally
(1)在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如资源回收,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的,finally中的代码一定会执行的
(2)finally 执行的时机是在方法返回之前(try 或者 catch 中如果有 return 会在这个 return 之前执行 finally),但是如果finally 中也存在 return 语句,那么就会执行 finally 中的 return, 从而不会执行到try中原有的 return
4.4异常的处理流程
(1)如果本方法中没有合适的处理异常的方式,就会沿着调用栈向上传递
(2)如果向上一直传递都没有合适的方法处理异常,最终就会交给 JVM 处理,程序就会异常终止,和我们最开始未使用 try catch 时是一样的
总结:
- 程序先执行 try 中的代码
- 如果 try 中的代码出现异常,就会结束 try 中的代码,看和 catch 中的异常类型是否匹配
- 如果找到匹配的异常类型就会执行 catch 中的代码
- 如果没有找到匹配的异常类型,就会将异常向上传递到上层调用者
- 无论是否找到匹配的异常类型,finally 中的代码都会被执行到
- 如果上层调用者也没有处理的了异常,就继续向上传递,一直到 main 方法也没有合适的代码处理异常,就会交给 JVM 来进行处理,此时程序就会异常终止
5.自定义异常
具体方式:
- 自定义异常类,然后继承自Exception(属于编译时异常或受查异常)或者 RuntimeException(属于运行时异常或非受查异常)
- 实现一个带有String类型参数的构造方法,参数含义是出现异常的原因
//自定义异常
class MyException extends RuntimeException{
public MyException() {
super();
}
public MyException(String s) {
super(s);
}
}
//编译时异常
class MyException2 extends Exception{
public MyException2() {
super();
}
public MyException2(String s) {
super(s);
}
}
public class TextDame {
public static void function1(){
int a = 10;
if(a == 10) {
throw new MyException("自定义异常");
}
}
public static void function2() throws MyException2 {
int a = 10;
if(a == 10) {
throw new MyException2("自定义异常");
}
}
public static void function3() {
try {
int a = 10 ;
if(a == 10) {
throw new MyException2("哈哈 我自己写的异常!");
}
}catch (MyException2 e) {
}
}
}