Java异常处理

本文深入介绍了Java中的异常处理,包括异常的概念、分类,如Exception和Error,以及如何抛出、声明和捕获异常。重点讨论了编译期异常和运行期异常的差异,并展示了自定义异常和JDK1.7后的try-with-resources新特性。文章通过实例代码帮助读者理解和掌握异常处理的各个方面。
摘要由CSDN通过智能技术生成

1. 异常处理

1. 学习内容

  1. 异常的概念
  2. 异常中的分类
  3. 抛出异常
  4. 声明异常
  5. 捕获异常
  6. 自定义异常
  7. 异常的补充
  8. JDK1.7之后的新特性try…with…resource

2. 学习目标

  1. 异常的概念–>理解
  2. 异常中的分类–>熟悉
  3. 抛出异常–>重点掌握
  4. 声明异常–>重点掌握
  5. 捕获异常–>重点掌握
  6. 自定义异常–>重点掌握
  7. 异常的补充–>熟悉
  8. JDK1.7之后的新特性try…with…resource–>重点掌握

3. 学习笔记

1. 异常的概念

程序中的异常是指程序执行途中出现的问题,例如:空指针,下标索引越界,类型转换异常–>这些异常会导致程序终止(停止运行)
异常处理就是用于解决程序执行中出现的问题
程序中的异常演示

public class Demo {
    public static void main(String[] args) {
        // 定义数组,并创建一个方法用于获取数组中的元素
        // 定义数组
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        // 调用方法获取数组指定下表数据
        int result = getArrayIndexElement(arr, 50);
        System.out.println("result = " + result);
    }

    /**
     * 指定数组下标索引获取数组数据
     *
     * @param arr   数组
     * @param index 下标索引
     * @return 返回数组元素
     */
    private static int getArrayIndexElement(int[] arr, int index) {
        // 通过判断解决数组下标索引越界的异常
        if (index < 0 || index > arr.length - 1) {
            // 如果越界则返回,在此处不管返回什么都不行,因为数据有可能会被使用到
            return -100000000;
        }
        return arr[index];
    }
}

2. 异常的分类

异常分类是指Java中提供的异常处理的不同类型
Java中提供的异常的祖宗(超类)Throwable(不算Object类),Java异常的祖宗类中定义了所有的异常以及错误的通用方法以及构造方法,以及异常信息的显示
Throwable类中又有两个子类:1. Exception,2. Error

  1. Exception:异常
    1. 异常是指代码问题所引发的错误,例如:空指针,下标越界等等这些都是代码引发的问题,可以通过代码解决的
    2. Exception:又分为两类异常:1. 编译期异常,2. 运行期异常
      1. 编译期异常:.java代码编写后无法正常通过编译的代码就是编译期异常
      2. 运行期异常:.java代码正常编译后,但是在运行期间出现的异常就是运行期异常:空指针,下标越界等等
  2. Error:错误
    1. 错误是指非代码问题,一般是由JVM虚拟机报出,并且无法通过代码解决,JVM优化或把代码删了,栈内存溢出就是错误
    2. 错误不是程序员能够解决的问题,只能找上级领导(JVM调优师加大内存)
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DsdDBHFC-1681914038116)(vx_images/169975415257189.png)]
      上图是Throwable类的家族体系

3. Throwable类–>熟悉

1. Throwable类概述

Throwable类是所有的错误以及异常的祖宗类,通常我们不需要创建它的对象,一般使用都是子孙类,所以我们只需要知道他的通用方法以及构造方法即可

2. Throwable类构造方法
  1. public Throwable():无参构造方法,用于创建对象(子孙类调用)
  2. public Throwable(String message):带参构造方法,用于指定当前的错误信息(自定义错误信息)
    1. message:需要指定的错误信息
3. Throwable类成员方法
  1. public String getMessage():返回异常的简单信息
  2. public String toString():返回异常的大概信息
  3. public void printStackTrace():直接显示异常的详细信息(等同于Java中的异常报错信息)

4. Error错误–>熟悉

1. Error错误概述

Error错误是指JVM虚拟机所报出的错误信息,等同于Windows电脑死机,所以程序员是无法解决这个问题的,并且一旦出现了Error错误那么就是严重问题,并且无法通过代码规避,解决方案:1. 删除代码(可以彻底解决),2. 更改代码逻辑(可以彻底解决),3. JVM虚拟机优化(无法彻底解决)

2. Error错误演示

Error错误通过栈溢出演示

public class Demo {
    public static void main(String[] args) {
        // 栈内存溢出错误演示
        main(args);
    }
}

5. Exception异常–>重点掌握

1. Exception异常概述

Exception异常是指Java程序中可以通过代码解决的问题,但是如果不解决也会造成JVM虚拟机停止运行
Exception异常分为:1. 编译期异常,2. 运行期异常

2. Exception异常分类
1. 编译期异常

编译期异常是指.java代码编写完成后无法通过编译器编译的代码,这种问题必须解决否则程序无法运行
编译期异常又被称为检查异常(CheckedException)
编译期异常是指Exception类以及子孙类(不包含RuntimeException类以及子孙类)
编译期异常演示

public class Demo {
    public static void main(String[] args) {
        // 创建FileInputStream类用于演示编译期异常
        // 当未处理且执行时会出现此问题:java: 未报告的异常错误java.io.FileNotFoundException; 必须对其进行捕获或声明以便抛出
        // 此问题如果不进行处理则无法通过编译,也就无法运行
        FileInputStream fis = new FileInputStream("");
    }
}
2. 运行期异常

运行期异常是指程序正常经过编译后再JVM运行途中发生的问题,例如:空指针,下标越界等等这些都属于是运行期异常
运行期异常又被称为非检查异常(UncheckedException)
运行期异常是指RuntimeException类以及子孙类
运行期异常代码案例

public class Demo {
    public static void main(String[] args) {
        // 演示运行期异常
        // 此处会产生:ArithmeticException: / by zero算数异常,除数为零
        int i = 1 / 0;
        System.out.println("i = " + i);
    }
}

6. 抛出异常–>重点掌握

1. 抛出异常概述

抛出异常是指在程序中指定位置将异常抛出,抛出异常不是最终处理它会导致程序异常的终止(与正常报错相同)
抛出异常使用关键字thorw
代码格式:throw new 异常类(编译期异常或运行期异常)

  1. 抛出编译期异常时必须做处理否则无法编译代码
  2. 抛出运行期异常时时在代码执行途中报错,然后终止程序运行
2. 抛出编译期异常
public class Demo {
    public static void main(String[] args) {
        // 调用编译期异常方法
        checkedException();
    }

    private static void checkedException() {
        // 抛出检查异常(编译期异常),编译期异常如果不做处理则无法编译也无法运行
        throw new Exception();
    }
}
3. 抛出运行期异常
public class Demo {
    public static void main(String[] args) {
        // 调用运行期异常方法
        uncheckedException();
    }

    private static void uncheckedException() {
        // 抛出非检查异常(运行期异常),程序执行时会出现JVM终止问题,与正常报错相同
        // 抛出异常时可以通过构造方法指定异常的信息
        throw new NullPointerException("您好,您当前出现了空指针异常!嘿嘿~~~");
    }
}
4. 抛出异常综合案例

场景1:创建方法用于获取数组下标索引元素,如果出现了非法的下标索引则将异常抛出并自定义异常信息

public class Demo {
    public static void main(String[] args) {
        // 场景:创建方法用于获取数组下标索引元素,如果出现了非法的下标索引则将异常抛出并自定义异常信息
        // 定义数组
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        // 调用方法获取数组元素
        int result = getArrayIndexElement(arr, 50);
        System.out.println("result = " + result);
    }

    /**
     * 获取数组元素方法
     *
     * @param arr   数组
     * @param index 下标索引
     * @return 返回数据
     */
    private static int getArrayIndexElement(int[] arr, int index) {
        // 判断下标索引是否合法
        if (index < 0 | index > arr.length - 1) {
            // 如果不合法则抛出异常
            throw new IndexOutOfBoundsException("您礼貌吗?数组多长心里没数吗?数组长度:0~" + (arr.length - 1) + ",而您输入的长度为:" + index);
        }
        // 正常返回数据
        return arr[index];
    }
}

场景2:使用Scanner控制台录入数据实现除法运算,如果用于将除数输入0则抛出异常并告诉这个熊货除数不能为零

public class Demo {
    public static void main(String[] args) {
        // 场景2:使用Scanner控制台录入数据实现除法运算,如果用于将除数输入0则抛出异常并告诉这个熊货除数不能为零
        // 创建Scanner对象
        Scanner input = new Scanner(System.in);
        // 输入两个数据
        System.out.print("请输入第一个数:");
        int number1 = input.nextInt();
        System.out.print("请输入第二个数:");
        int number2 = input.nextInt();
        // 调用除法运算方法
        int result = division(number1, number2);
        System.out.println("result = " + result);
    }

    /**
     * 除法运算方法
     *
     * @param number1 数值1
     * @param number2 数值2
     * @return 返回运算结果
     */
    private static int division(int number1, int number2) {
        // 判断除数是否为0
        if (number2 == 0) {
            // 抛出异常,如果忘记了异常类的单词则可以使用RuntimeException
            // throw new RuntimeException("您个熊货,您不知道除数不能为零吗?");
            throw new ArithmeticException("您个熊货,您不知道除数不能为零吗?");
        }
        // 如果数据没问题则返回运算结果
        return number1 / number2;
    }
}

7. 声明异常–>重点掌握

1. 声明异常概述

声明异常是指如果有编译期异常且在当前位置不想做处理则可以将异常声明出去交给调用者处理,如果到最后都没有人处理这个异常则声明给JVM虚拟机,到JVM虚拟机后会报错并终止程序的运行
声明异常使用关键字thorws
代码格式:throws 异常类1,异常类2,异常类n...(注意:如果异常过多可以直接使用Exception统一声明处理)

  1. 注意:声明异常一般只针对于编译期异常
2. 声明运行期异常–>了解
public class Demo {
    public static void main(String[] args) throws Exception {
        // 调用声明运行期异常方法
        uncheckedException();
    }

    /**
     * 声明运行期异常
     *
     * @throws RuntimeException 运行期异常祖宗类(最大的)
     */
    private static void uncheckedException() throws RuntimeException {
    }
}
3. 声明编译期异常–>掌握
public class Demo {
    public static void main(String[] args) throws Exception {
        // 调用声明编译期异常方法
        checkedException();
    }

    /**
     * 声明编译期异常
     *
     * @throws Exception   编译期异常祖宗类(最大的)
     * @throws IOException 声明IO编译期异常,如果异常中声明了Exception则可以省略声明其他的
     */
    private static void checkedException() throws Exception, IOException {
    }
}
4. 声明异常综合案例

场景:Student实体类中定义性别时如果输入非男非女的内容则抛出编译期异常,在测试类调用设置方式并处理这个异常

  1. 实体类
public class Student {
    private Integer id;
    private String name;
    private String gender;

    public Student() {
    }

    public Student(Integer id, String name, String gender) throws Exception {
        this.id = id;
        this.name = name;
        // 调用通用的设置性别方法
        setGender(gender);
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    /**
     * 设置性别方法,用于设置性别时验证性别是否合法
     *
     * @param gender 传入性别参数
     * @throws Exception 声明编译期异常类
     */
    public void setGender(String gender) throws Exception {
        // 判断输入的性别是否是男或女,如果不是则抛出编译期异常
        if (!"男".equals(gender) && !"女".equals(gender)) {
            // 抛出异常
            throw new Exception("您输入的性别不存在,请验证一下再次输入!");
        }
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
}
  1. 测试类
public class Demo {
    public static void main(String[] args) throws Exception {
        Student student = new Student();
        // java: 未报告的异常错误java.lang.Exception; 必须对其进行捕获或声明以便抛出
        // 此处需要将异常声明出去
        student.setGender("男");
        student.setId(1);
        student.setName("彭于晏");
        System.out.println("student = " + student);
    }
}

8. 捕获异常(最终处理)–>重点掌握

1. 捕获异常概述

捕获异常是将程序中出现的异常进行捕获处理,经过捕获处理后程序不会再因为异常而终止

2. 捕获异常格式
1. 格式一
try {
    // 有可能会出现异常的代码
} catch(处理异常类型) {
    // 处理的结果方案(输出错误信息)
}
2. 格式二
try {
    // 有可能会出现异常的代码
} finally {
    // 最终执行的内容(无论是否发生异常都会执行),但是不处理异常程序同样会导致异常的终止
}
3. 格式三
try {
    // 有可能会出现异常的代码
} catch(处理异常类型) {
    // 处理的结果方案(输出错误信息)
} finally {
    // 最终执行的内容(无论是否发生异常都会执行),但是不处理异常程序同样会导致异常的终止
}
3. 捕获异常代码案例
1. 格式一代码案例
try {
    // 有可能会出现异常的代码
} catch(处理异常类型) {
    // 处理的结果方案(输出错误信息)
}
public class Demo {
    public static void main(String[] args) {
        // try块
        try {
            // 调用方法,触发运行期异常,可以使用try...catch解决此问题
            func();
        } catch (NullPointerException e) {
            // 调用Throwable类的方法
            // 1. `public String getMessage()`:返回异常的简单信息
            String message = e.getMessage();
            System.out.println("message = " + message);
            System.err.println(message);
            // 2. `public String toString()`:返回异常的大概信息
            String toString = e.toString();
            System.err.println(toString);
            System.out.println("toString = " + toString);
            // 3. `public void printStackTrace()`:直接显示异常的详细信息(等同于Java中的异常报错信息)
            e.printStackTrace();
        } /*catch (IndexOutOfBoundsException e) {// 如果异常类型不同则无法处理异常
            // 调用Throwable类的方法
            // 1. `public String getMessage()`:返回异常的简单信息
            String message = e.getMessage();
            System.out.println("message = " + message);
            System.err.println(message);
            // 2. `public String toString()`:返回异常的大概信息
            String toString = e.toString();
            System.err.println(toString);
            System.out.println("toString = " + toString);
            // 3. `public void printStackTrace()`:直接显示异常的详细信息(等同于Java中的异常报错信息)
            e.printStackTrace();
        }*/
        // 随意输出一句话
        System.out.println("程序正常结束...");
    }

    public static void func() {
        // 抛出运行期异常
        throw new NullPointerException("抛出空指针异常!");
    }
}
2. 格式二代码案例
try {
    // 有可能会出现异常的代码
} finally {
    // 最终执行的内容(无论是否发生异常都会执行),但是不处理异常程序同样会导致异常的终止
}
public class Demo {
    public static void main(String[] args) {
        // try块
        try {
            // 调用抛出异常的方法
            func();
        } finally {// 最终执行但不代表它会处理异常
            // 最终执行的代码,不管是否发生异常都会执行
            System.out.println("finally...");
        }
        // 随意输出一句话
        System.out.println("程序正常结束...");
    }

    public static void func() {
        // 抛出运行期异常
        throw new NullPointerException("抛出空指针异常!");
    }
}
3. 格式三代码案例
try {
    // 有可能会出现异常的代码
} catch(处理异常类型) {
    // 处理的结果方案(输出错误信息)
} finally {
    // 最终执行的内容(无论是否发生异常都会执行),但是不处理异常程序同样会导致异常的终止
}
public class Demo {
    public static void main(String[] args) {
        // try块
        try {
            // 调用抛出异常的方法
            func();
            // 随意输出一句话
            System.out.println("try...");
        } catch (NullPointerException e) {
            // 处理异常
            e.printStackTrace();
        } finally {
            // 最终执行
            System.out.println("finally...");
        }
        // 随意输出一句话
        System.out.println("程序正常结束...");
    }

    public static void func() {
        // 抛出运行期异常
        throw new NullPointerException("抛出空指针异常!");
    }
}
4. 捕获异常多异常处理

如果捕获异常时发生多个异常时如何处理

1. 解决方案一
public class Demo {
    public static void main(String[] args) {
        // try块
        try {
            // 调用抛出异常方法
            func();
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
        } catch (ClassCastException e) {
            e.printStackTrace();
        }
        // 随意输出一句话
        System.out.println("程序正常结束...");
    }

    public static void func() {
        // 获取随机数
        Random random = new Random();
        int randomInt = random.nextInt(4);
        switch (randomInt) {
            case 0:
                // 抛出运行期异常
                throw new NullPointerException("抛出空指针异常!");
            case 1:
                // 抛出运行期异常
                throw new IndexOutOfBoundsException("下标索引越界异常!");
            case 2:
                // 抛出运行期异常
                throw new ArithmeticException("算数异常!");
            case 3:
                // 抛出运行期异常
                throw new ClassCastException("类型转换异常!");
        }
    }
}
2. 解决方案二
public class Demo {
    public static void main(String[] args) {
        try {
            // 调用抛出异常的方法
            func();
        } catch (NullPointerException | ArithmeticException | IndexOutOfBoundsException | ClassCastException e) {
            e.printStackTrace();
        }
        // 随意输出一句话
        System.out.println("程序正常结束...");
    }

    public static void func() {
        // 获取随机数
        Random random = new Random();
        int randomInt = random.nextInt(4);
        switch (randomInt) {
            case 0:
                // 抛出运行期异常
                throw new NullPointerException("抛出空指针异常!");
            case 1:
                // 抛出运行期异常
                throw new IndexOutOfBoundsException("下标索引越界异常!");
            case 2:
                // 抛出运行期异常
                throw new ArithmeticException("算数异常!");
            case 3:
                // 抛出运行期异常
                throw new ClassCastException("类型转换异常!");
        }
    }
}
3. 解决方案三
public class Demo {
    public static void main(String[] args) {
        // try块
        try {
            // 调用抛出异常方法
            func();
            // 当使用Exception(处理所有编译期以及运行期异常)
            // 当使用RuntimeException(只处理运行期异常)
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 随意输出一句话
        System.out.println("程序正常结束...");
    }

    public static void func() {
        // 获取随机数
        Random random = new Random();
        int randomInt = random.nextInt(5);
        // randomInt = 4;
        switch (randomInt) {
            case 0:
                // 抛出运行期异常
                throw new NullPointerException("抛出空指针异常!");
            case 1:
                // 抛出运行期异常
                throw new IndexOutOfBoundsException("下标索引越界异常!");
            case 2:
                // 抛出运行期异常
                throw new ArithmeticException("算数异常!");
            case 3:
                // 抛出运行期异常
                throw new ClassCastException("类型转换异常!");
            case 4:
                // 抛出运行期异常
                throw new NoSuchElementException("没有这样的元素异常!");
        }
    }
}
5. 捕获异常综合案例

场景:学生类中判断传入的性别是否合法,如果不合法抛出编译期异常,并在调用时捕获异常

  1. 学生类
public class Student {
    private Integer id;
    private String name;
    private String gender;

    public Student() {
    }

    public Student(Integer id, String name, String gender) throws Exception {
        this.id = id;
        this.name = name;
        // 调用通用的设置性别方法
        setGender(gender);
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    /**
     * 设置性别方法,用于设置性别时验证性别是否合法
     *
     * @param gender 传入性别参数
     * @throws Exception 声明编译期异常类
     */
    public void setGender(String gender) throws Exception {
        // 判断输入的性别是否是男或女,如果不是则抛出编译期异常
        if (!"男".equals(gender) && !"女".equals(gender)) {
            // 抛出异常
            throw new Exception("您输入的性别不存在,请验证一下再次输入!");
        }
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
}
  1. 测试类
public class Demo {
    public static void main(String[] args) {
        // 创建学生类对象
        Student student = new Student();
        try {
            student.setId(1);
            student.setName("李易峰");
            student.setGender("嬲");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("student = " + student);
    }
}

9. 异常处理的三种方式区别总结

1. 抛出异常

在方法中使用,用于将异常直接抛出,可以抛出编译期异常以及运行期异常,但是抛出编译期异常后必须做处理(捕获或声明),会导致程序的异常终止

2. 声明异常

在方法形参后面使用,一次可以声明多个异常,可以声明编译期异常以及运行期异常,但是声明编译期异常调用者必须做处理(捕获或声明),如果方法中存在异常则终止程序,如果没有异常则不会终止程序

3. 捕获异常–>后期只要是出现异常,不管在哪个位置最终必须进行捕获处理

在方法体内使用,用于最终处理异常错误,try块用于处理可能会发生异常的代码,catch块用于处理异常(一般用于打印错误信息),finally块无论是否发生异常最终都会执行的代码块

10. 异常补充

1. finally最终运行测试–>重点掌握

finally最终运行测试假设在使用try…catch…finally时使用return关键字时是否还会执行finally代码块

public class Demo {
    public static void main(String[] args) {
        int result = func();
        System.out.println("result = " + result);
    }

    public static int func() {
        // 声明变量
        int i = 0;
        // try...catch...finally
        try {
            // 异常
            // int i1 = 1 / 0;
            // 关闭虚拟机,finally则不会执行
            System.exit(0);
            // 更新变量
            return ++i;
        } catch (Exception e) {
            // 更新变量
            return ++i;
        } finally {
            System.out.println("i = " + i);
            // 更新变量,不管return结束方法在哪里调用,finally始终都会执行
            return ++i;
        }
    }
}
2. 声明异常是否会被继承影响–>熟悉

具有父子关系的类是否可以被声明异常所影响

  1. 父类
/**
 * 父类
 */
public class Father {
    /**
     * 编译期异常
     *
     * @throws IOException 编译期异常
     */
    public void func01() throws IOException {

    }

    /**
     * 编译期异常
     *
     * @throws Exception 编译期异常
     */
    public void func02() throws Exception {

    }

    /**
     * 运行期异常
     *
     * @throws IndexOutOfBoundsException 运行期异常
     */
    public void func03() throws IndexOutOfBoundsException {

    }

    /**
     * 运行期异常
     *
     * @throws RuntimeException 运行期异常
     */
    public void func04() throws RuntimeException {

    }

    /**
     * 无异常
     */
    public void func05() {

    }
}
  1. 子类
/**
 * 子类继承Father类
 */
public class Son extends Father {
    /**
     * 编译期异常,子类声明时可以比父类的小但是不能比父类的大
     *
     * @throws IOException 编译期异常
     */
    @Override
    public void func01() throws EOFException {
    }

    /**
     * 编译期异常,子类声明时可以比父类的小但是不能比父类的大
     *
     * @throws Exception 编译期异常
     */
    @Override
    public void func02() throws Exception {
    }

    /**
     * 运行期异常,子类可以比父类大但是最多到RuntimeException,也可以比父类小
     *
     * @throws IndexOutOfBoundsException 运行期异常
     */
    @Override
    public void func03() throws RuntimeException {
    }

    /**
     * 运行期异常,子类可以比父类大但是最多到RuntimeException,也可以比父类小
     *
     * @throws RuntimeException 运行期异常
     */
    @Override
    public void func04() throws IndexOutOfBoundsException {
    }

    /**
     * 无异常,如果父类没有异常则子类只能给运行期异常,编译期不行
     */
    @Override
    public void func05() throws RuntimeException {
    }
}
3. 异常连

异常连是指方法中向外声明编译期异常,但是调用者不想处理同样向外声明,无限形成异常链

public class Demo {
    public static void main(String[] args) {
        try {
            // 调用func01方法,到最终后必须做处理
            func01();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void func01() throws Exception {
        // 调用func02方法
        func02();
    }

    public static void func02() throws Exception {
        // 调用func03方法
        func03();
    }

    public static void func03() throws Exception {
        // 调用func04方法
        func04();
    }

    public static void func04() throws Exception {
        System.out.println("func04...");
    }
}

11. 自定义异常–>重点掌握

1. 自定义异常概述

自定义异常是指开发人员自定义自己的异常信息类,这种方式可以处理自己定义的异常错误信息,可以更加简单明了的知道问题
自定义异常分为两大类:1. 自定义编译期异常,2. 自定义运行期异常

  1. 自定义编译期异常只需要继承Exception
  2. 自定义运行期异常只需要继承RuntimeException
    注意:继承后可以不重写任何方法,但是得重写构造方法(实现自己的构造方法并调用super父类的,等同于与官方相同),如果不需要异常信息则构造方法也不用定义
2. 自定义编译期异常
  1. 自定义异常类
/**
 * 自定义编译期异常
 */
public class CustomException extends Exception {
    public CustomException() {
        // 空参构造方法调用带参构造方法,设置默认异常信息
        this("自定义异常...");
    }

    public CustomException(String message) {
        super(message);
    }
}
  1. 测试类
public class Demo {
    public static void main(String[] args) throws CustomException {
        try {
            // 自定义的异常类可以抛出,也可以声明,同样也可以捕获
            throw new CustomException("抛出自定义编译期异常...");
        } catch (CustomException e) {
            e.printStackTrace();
        }
    }
}
3. 自定义运行期异常
  1. 自定义异常类
/**
 * 自定义运行期异常
 */
public class CustomRuntimeException extends RuntimeException {
    public CustomRuntimeException() {
        this("默认异常信息...");
    }

    public CustomRuntimeException(String message) {
        super(message);
    }
}
  1. 测试类
public class Demo {
    public static void main(String[] args) {
        try {
            // 自定义的异常类可以抛出,也可以声明,同样也可以捕获
            throw new CustomRuntimeException("抛出自定义运行期异常...");
        } catch (CustomRuntimeException e) {
            e.printStackTrace();
        }
    }
}
4. 自定义异常综合案例

场景:学生类性别如果非法则抛出自定义运行期异常,提示调用

  1. 自定义异常类
/**
 * 自定义性别异常类
 */
public class GenderIllegalException extends RuntimeException {
    public GenderIllegalException() {
        this("性别异常...");
    }

    public GenderIllegalException(String message) {
        super(message);
    }
}
  1. 实体类
public class Student {
    private Integer id;
    private String name;
    private String gender;

    public Student() {
    }

    public Student(Integer id, String name, String gender) {
        this.id = id;
        this.name = name;
        // this.gender = gender;
        // 调用setGender非法
        setGender(gender);
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        // 判断性别是否合法,如果不合法则抛出自定义性别非法异常,如果合法则正常运行
        if (!"男".equals(gender) && !"女".equals(gender)) {
            throw new GenderIllegalException("输入的性别非法,只允许男或女,而您这个狗东西输入的是" + gender);
        }
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
}
  1. 测试类
public class Demo {
    public static void main(String[] args) {
        // 创建学生类
        Student student = new Student();
        // 设置数据
        student.setId(1);
        student.setName("彭于晏");
        student.setGender("男神");
        System.out.println("student = " + student);
    }
}

// 作业:场景–>年龄输入时只允许1~160范围,如果超出范围则抛出自定义异常错误,异常捕获处理一下

12. JDK1.7后新增try…with…resource特性

1. JDK1.7后新增try…with…resource特性概述

JDK1.7后新增try…with…resource特性是针对于捕获异常的升级版,可以自动释放代码资源(例如:Scanner使用完毕后需要关闭通道释放资源)
释放资源的必要条件是类必须实现CloseableAutoCloseable任意一个接口,并且重写close方法

2. try…with…resource语法格式
1. 格式一
try (需要自动释放资源的类,例如:Scanner) {
    // 会出现异常的代码或使用小括号中定义的类的方法
}
2. 格式二
try (需要自动释放资源的类,例如:Scanner) {
    // 会出现异常的代码或使用小括号中定义的类的方法
} catch(异常处理类型) {
    // 异常处理
}
3. 格式三
try (需要自动释放资源的类,例如:Scanner) {
    // 会出现异常的代码或使用小括号中定义的类的方法
} finally {
    // 最终执行的代码
}
4. 格式四
try (需要自动释放资源的类,例如:Scanner) {
    // 会出现异常的代码或使用小括号中定义的类的方法
} catch(异常处理类型){
    // 异常处理
} finally {
    // 最终执行的代码
}
3. try…with…resource代码案例
/**
 * try...with...resource代码案例
 */
public class Demo {
    public static void main(String[] args) {
        // // 创建Scanner类
        // Scanner input = new Scanner(System.in);
        // System.out.print("随意输入内容:");
        // String next = input.next();
        // System.out.println("next = " + next);
        // // 释放资源关闭通道
        // input.close();
        // System.out.print("随意输入内容:");
        // next = input.next();
        // System.out.println("next = " + next);
        // 调用方法
        // func01();
        // func02();
        // func03();
        func04();
    }

    public static void func01() {
        try (Scanner input = new Scanner(System.in)) {
            // 随意输入数据
            System.out.print("随意输入内容:");
            String next = input.next();
            System.out.println("next = " + next);
        }// try块执行完毕后会自动调用close方法
    }

    public static void func02() {
        try (Scanner input = new Scanner(System.in)) {
            // 出现错误
            int i = 1 / 0;// 如果执行中出现了异常也会处理
            // 随意输入数据
            System.out.print("随意输入内容:");
            String next = input.next();
            System.out.println("next = " + next);
        } catch (Exception e) {
            System.out.println("异常处理...");
        }
    }

    public static void func03() {
        try (Scanner input = new Scanner(System.in)) {
            // 随意输入数据
            System.out.print("随意输入内容:");
            String next = input.next();
            System.out.println("next = " + next);
        } finally {
            System.out.println("最终执行的代码...");
        }
    }

    public static void func04() {
        try (Scanner input = new Scanner(System.in)) {
            // 随意输入数据
            System.out.print("随意输入内容:");
            String next = input.next();
            System.out.println("next = " + next);
        } catch (Exception e) {
            System.out.println("异常处理...");
        } finally {
            System.out.println("最终执行的代码...");
        }
    }
}
3. AutoCloseable以及Closeable接口的重写测试–>了解
1. AutoCloseable
  1. 实现类
public class AutoCloseableImpl implements AutoCloseable {
    public void func() {
        System.out.println("调用方法...");
    }

    @Override
    public void close() {
        System.out.println("close方法被调用...");
    }
}
  1. 测试类
public class Demo {
    public static void main(String[] args) {
        // JDK1.7新特性try...with...resource
        try (AutoCloseableImpl autoCloseable = new AutoCloseableImpl()) {
            autoCloseable.func();
            System.out.println("随意输出...");
        }
    }
}
2. Closeable
  1. 实现类
public class CloseableImpl implements Closeable {
    public void func() {
        System.out.println("调用方法...");
    }

    @Override
    public void close() {
        System.out.println("close方法被调用...");
    }
}
  1. 测试类
public class Demo {
    public static void main(String[] args) {
        // JDK1.7新特性try...with...resource
        try (CloseableImpl closeable = new CloseableImpl()) {
            closeable.func();
            System.out.println("随意输出...");
        }
    }
}
3. 注意事项

AutoCloseable和Closeable中都有声明编译期异常,如果代码中没有异常则直接删除即可,如果有异常则需要使用catch捕获

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值