目录

一、异常概述

1、简介

2、异常体系

3、编译期异常的2种处理方式

①上抛给虚拟机处理(缺点是虚拟机拿到异常后悔终止程序)

②通过try...catch处理(好处是出现异常之后后续代码继续执行)

4、运行期异常

5、Error错误

二、分析异常产生的过程

三、异常的处理

throw关键字

作用:

使用格式:

注意:

四、Objects非空判断

五、异常处理的第一种方式(上抛异常)

throws关键字:

作用:

使用格式(在方法声明时使用):

注意:

六、异常处理的第二种方式(捕获异常)

try...catch法

格式:

注意:

代码演示:

七、Throwable中3个处理异常的方法

1、String getMessage():

2、String toString():

3、void printStackTrace():

4、代码示例

异常信息:

八、finally代码块

finally代码块:

格式如下(try和finally只能是一个,catch可以是多个):

注意:

九、多个异常的捕获

1、三种处理方式:

2、注意

3、代码示例

十、finally代码块种有return语句的情况

十一、子父类异常

概述:

十二、自定义异常类

1、概述

2、格式

3、注意

4、代码示例


一、异常概述

1、简介

异常指的是在程序执行过程中,出现的非正常情况,最终导致jvm非正常停止;

(异常并不是指语法错误,语法错误,编译不通过,不会产生字节码文件,就不会运行;)

 

2、异常体系

异常类Throwable有两个子类:Error(不能处理的错误)和Exception(可处理的异常),我们平常所说的异常指的是Exception;

Exception:编译(写代码)期异常(可处理的异常);

RuntimeException:运行期异常(可处理的异常);

 

3、编译期异常的2种处理方式

①上抛给虚拟机处理(缺点是虚拟机拿到异常后悔终止程序)

public class MyException {
    //将异常上抛给虚拟机处理,出现异常虚拟机悔停止程序运行
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = sdf.parse("1999-09-09");
    }
}

②通过try...catch处理(好处是出现异常之后后续代码继续执行)

public class MyException {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date date = sdf.parse("1999-0909");
        } catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println("后续代码继续执行");
    }
}

异常:

java.text.ParseException: Unparseable date: "1999-0909"
	at java.base/java.text.DateFormat.parse(DateFormat.java:395)
	at study.exception.MyException.main(MyException.java:11)
后续代码继续执行

 

4、运行期异常

public class MyException {
    public static void main(String[] args) {
        //下面演示运行期异常
        int[] arr = {1,2,3};
        try {
            System.out.println(arr[3]);
        }catch (Exception e){
            System.out.println(e);//打印这个异常
            //java.lang.ArrayIndexOutOfBoundsException: 3
        }
        System.out.println("后续代码继续执行");
    }
}

 

5、Error错误

public class MyException {
    public static void main(String[] args) {
        //Error错误
        int[] arr = new int[1024*1024*1024];
        //java.lang.OutOfMemoryError: Java heap space
    }
}

 

二、分析异常产生的过程

Java异常详解_java

 

三、异常的处理

throw关键字

作用:

可以使用throw关键字在指定的方法中抛出指定的异常;

使用格式:

throw new XXXException("异常产生的原因");

注意:

①throw关键字必须写在方法的内部;

②throw关键字关键字后面new的对象必须是Exception对象或Exception子类的对象;

③throw关键字抛出指定的异常对象,我们必须处理:

  • throw关键字后面创建的是RuntimeExpection或者是RuntimeException的子类,默认不处理,交给Jvm处理;
  • throw关键字后面是编译(写代码)异常,我们必须处理,要么上抛处理,要么try...catch;

以后工作中:

我们必须对方法接收的参数进行合法性校验,若参数不合法则通过抛出异常的方式告诉调用者;

例如(备注:这里作为演示,其实这两个异常都是运行期异常,JVM会自动处理):

public class MyException {
    public static void main(String[] args) {
        int[] a = {};
        System.out.println(getElement(a,0));
    }
    private static int getElement(int[] arr,int index){
        if(arr == null){
            throw new NullPointerException("传入的数组为空");
        }else if(index > arr.length-1){
            throw new ArrayIndexOutOfBoundsException("传递的索引值超出了数组的长度");
        }
        return arr[index];
    }
}

所抛出的异常:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 传递的索引值超出了数组的长度
	at study.exception.MyException.getElement(MyException.java:13)
	at study.exception.MyException.main(MyException.java:7)

 

四、Objects非空判断
public class MyObjects_NonNull {
    public static void main(String[] args) {
        //判断一个对象是否为空
        System.out.println(Objects.nonNull(null));//false
        //跟想象中不太一样,用的时候要再深入研究
        System.out.println(Objects.nonNull(""));//true
        int[] a = {};
        //跟想象中不太一样,用的时候要再深入研究
        System.out.println(Objects.nonNull(a));//true
    }
}

 

五、异常处理的第一种方式(上抛异常)

throws关键字:

异常处理的第一种方式:交给别人处理;

作用:

当方法内部抛出异常对象的时候,就必须对这个异常对象进行处理;

可以使用throws关键字将异常抛给调用者处理——最终抛给JVM处理(JVM终端程序的执行);

使用格式(在方法声明时使用):

修饰符 返回值类型 方法名(参数列表) throws AAAException,BBBException...{
    throw new AAAException("产生原因");
    throw new BBBException("产生原因");
    ……
}

注意:

①throws关键字必须写在方法声明处;

②throws关键字后面声明的异常必须是Exception或者是Exception的子类;

③方法内部如果抛出了多个异常,那么throws后面也必须声明多个异常(若有子父类关系,那么直接声明父类即可);

④调用了一个方法抛出的异常,我们就必须处理声明的异常:

  • 要么交给方法调用者处理,最终交给JVM;
  • 要么交给try...catch自己处理;
package study.exception;

import java.io.FileNotFoundException;

public class MyObjects_NonNull {
    //上抛给调用者处理-JVM虚拟机
    public static void main(String[] args) throws FileNotFoundException {
        getFile("D://a.txt");
    }
    //上抛给调用者处理-main方法
    private static void getFile(String path) throws FileNotFoundException {
        if(!path.equals("C://a.txt")){
            throw new FileNotFoundException("未传入指定文件路径");
        }
    }
}

异常:

Exception in thread "main" java.io.FileNotFoundException: 未传入指定文件路径
	at study.exception.MyObjects_NonNull.getFile(MyObjects_NonNull.java:13)
	at study.exception.MyObjects_NonNull.main(MyObjects_NonNull.java:8)

 

六、异常处理的第二种方式(捕获异常)

try...catch法

格式:

    try{
        //可能产生异常的代码
    }catch(异常1){
        //出现异常1之后的处理逻辑
    }catch(异常2){
        //出现异常2之后的处理逻辑
    }
    //catch可以有多个,try只能有一个

注意:

①try若可能抛出多个异常,可以用多个catch,但只能有一个try;

②如果try中产生了异常,就会执行相应的catch里面的异常处理逻辑,执行完catch之后还会继续执行try...catch之后的代码;

反之,如果try中没有产生异常,就不会执行catch里面的异常处理逻辑,try里面的代码执行完毕之后执行try...catch之后的代码;

代码演示:

package study.exception;

import java.io.FileNotFoundException;
import java.io.IOException;

public class MyObjects_NonNull {
    public static void main(String[] args) {
        //可能产生的异常不再上抛,直接处理
        try {
            //可能产生异常的代码
            getFile("C://a.tx");
        } catch (IOException e) {
            //出现异常之后的处理逻辑
            e.printStackTrace();//输出异常
        }
        System.out.println("后续代码继续执行");
    }
    //上抛给调用者处理-main方法
    private static void getFile(String path) throws IOException {
        if(!path.equals("C://a.txt")){
            throw new FileNotFoundException("未传入指定文件路径");
        }
    }
}

 

七、Throwable中3个处理异常的方法

1、String getMessage():

返回此throwable的简短描述

2、String toString():

返回throwable详细消息字符串

3、void printStackTrace():

JVM打印异常对象,默认调用此方法(异常信息最全面)

4、代码示例

package study.exception;

import java.io.FileNotFoundException;
import java.io.IOException;

public class MyObjects_NonNull {
    public static void main(String[] args) {
        //可能产生的异常不再上抛,直接处理
        try {
            //可能产生异常的代码
            getFile("C://a.tx");
        } catch (IOException e) {
            //出现异常之后的处理逻辑
            e.printStackTrace();//输出异常
            System.out.println(e.toString());
            System.out.println(e.getMessage());
        }
        System.out.println("后续代码继续执行");
    }
    //上抛给调用者处理-main方法
    private static void getFile(String path) throws IOException {
        if(!path.equals("C://a.txt")){
            throw new FileNotFoundException("未传入指定文件路径");
        }
    }
}

异常信息:

(最全面的异常e.printStackTrace();)
java.io.FileNotFoundException: 未传入指定文件路径
	at study.exception.MyObjects_NonNull.getFile(MyObjects_NonNull.java:23)
	at study.exception.MyObjects_NonNull.main(MyObjects_NonNull.java:11)
(返回throwable详细消息字符串System.out.println(e.toString());)
java.io.FileNotFoundException: 未传入指定文件路径
(返回此throwable的简短描述System.out.println(e.getMessage());)
未传入指定文件路径
后续代码继续执行

 

八、finally代码块

finally代码块:

有一些代码是否出现异常都要执行,就可以写在finally代码块中;

格式如下(try和finally只能是一个,catch可以是多个):

        try {
            //可能产生异常的代码
        }catch (/*异常种类*/){
            //出现异常之后的处理逻辑
        }catch (/*异常种类*/){
            //出现异常之后的处理逻辑
        }finally {
            //是否产生异常都会执行的代码
        }

注意:

①若try中有多行代码,那么前面的代码出现异常的时候后面的代码就不能执行了,所以可以放在finally中执行;

②finally不能单独使用;

③finally代码块一般用于资源释放,无论是否出现异常都会执行;

 

九、多个异常的捕获

1、三种处理方式:

①分别捕获和处理;

②多个异常,一次捕获,多次处理;

③多个异常,一次捕获,一次处理;

2、注意

①一个try多个catch,如果异常有子父类关系,子类必须写在父类上面,否则会报错;

②如果try中存在两个可能存在的异常,当第一个出现异常,try中的后续代码也是不能执行的;

3、代码示例

package study.exception;

import java.util.List;

public class ManyException {
    public static void main(String[] args) {
        //1、分别捕获和处理
        try {
            int[] x = {1,2,3};
            System.out.println(x[3]);//ArrayIndexOutOfBoundsException: 3
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e.toString());
        }
        try {
            List<Integer> list = List.of(1,2,3);
            System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
        }catch (IndexOutOfBoundsException e){
            System.out.println(e.toString());
        }
        //2、一次捕获,多次处理
        try {
            int[] x = {1,2,3};
            System.out.println(x[3]);//ArrayIndexOutOfBoundsException: 3
            System.out.println("try中后续代码");
            List<Integer> list = List.of(1,2,3);
            System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e.toString());
        }catch (IndexOutOfBoundsException e){
            System.out.println(e.toString());
        }
        //3、一次捕获,一次处理
        try {
            int[] x = {1,2,3};
            System.out.println(x[3]);//ArrayIndexOutOfBoundsException: 3
            System.out.println("try中后续代码");
            List<Integer> list = List.of(1,2,3);
            System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
        }catch (IndexOutOfBoundsException e){
            //IndexOutOfBoundsException一个异常可以收多种错误(父类)
            System.out.println(e.toString());
        }
    }
}

 

十、finally代码块种有return语句的情况

如果finally代码块种有return语句的情况,永远返回finally中的结果,应该避免该情况;

其实不太懂具体啥意思,以后使用到要细细研究!

 

十一、子父类异常

概述:

①如果父类抛出了多个异常,子类重写父类方法时,要抛出和父类相同的异常或者父类的子类的异常或者不抛出异常;

②如果父类没有抛出异常,子类重写父类的方法也不可能抛出异常,此时子类产生异常,只能捕获处理,不能声明抛出;

 

十二、自定义异常类

1、概述

定义一个异常类跟写一个普通类相似,但要继承Exception或者RuntimeExpection

2、格式

    public class XXXException extends Exception | RuntimeException{
        //添加一个无参构造方法
        //添加一个带异常信息的构造方法
    }

3、注意

①自定义异常类一般都以Exception结尾,说明该类是一个异常类;

②自定义异常类必须要继承Exception或者RuntimeExpection;

  • 继承Exception:是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理此异常(要么throws要么try...catch);
  • 继承RuntimeExpection:无需处理,交给虚拟机处理即可——中断程序;

4、代码示例

public class MyDiyException extends Exception {
    //无参构造
    public MyDiyException() {
        super();
    }
    //带异常信息的构造
    public MyDiyException(String e){
        //父类有带异常信息的构造,直接交给父类处理
        super(e);
    }
}