• JavaSE 第九章 异常


    9.1 异常概述与异常体系结构

    在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美, 在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码能够避 免的,比如:客户输入数据的格式,读取文件是否存在,网络是否始终保持通畅等等。

    • 异常:在Java语言中,将程序执行中发生的不正常情况称为“异常” 。 (开发过程中的语法错误和逻辑错误不是异常)

    • Java程序在执行过程中所发生的异常事件可分为两类:

      • Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性 的代码进行处理。

      • Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使 用针对性的代码进行处理。例如: 空指针访问 、试图读取不存在的文件 、网络连接中断 、数组角标越界

    • 对于这些错误,一般有两种解决方法:一是遇到错误就终止程序 的运行。另一种方法是由程序员在编写程序时,就考虑到错误的 检测、错误消息的提示,以及错误的处理。

    • 捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。 比如:除数为0,数组下标越界等

    • 分类:编译时异常和运行时异常

    9.1.1 运行时异常

    • 运行时异常是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免的。java.lang.RuntimeException类及其子类都是运行时异常

    在这里插入图片描述

    • 之前所遇到过的ClassCastExceptionArrayIndexOutOfBoundsExceptionNullPointerException都属于运行时异常
    • 对于这类异常可以不做处理,因为这类异常很普遍,若是全处理,可能会对程序的可读性和运行效率产生影响

    8.1.2 编译时异常

    • 编译时异常是指编译器要求必须处理的异常,即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常

    • 对于这类异常,如果程序不处理,可能会带来意想不到的结果

    9.2 常见异常

    • java.lang.RuntimeException 运行时异常

      • ClassCastException 类转换异常
      • ArrayIndexOutOfBoundsException 数组下标越界异常
      • NullPointerException 空指针异常
      • NumberFormatException 数字类型异常
    • java.io.IOException IO异常

      • FileNotFoundException 文件没找到异常
      • EOFException 流结束异常
    • java.lang.ClassNotFoundException 类没找到异常

    • java.sql.SQLException sql异常

    9.2.1 ArrayIndexOutOfBoundsException数组下标越界异常

    • 访问到并不存在的数组空间
    /**
     * 数组下标越界异常
     */
    public class ArrayIndexOutOfBoundsException {
        public static void main(String[] args) {
            int[] arr = new int[5] ;
    
            System.out.println(arr[5]);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    9.2.2 NullPointerException 空指针异常

    • 引用数据类型通过 . 去调用方法或属性时,如果引用数据类型为null,则会报错
    /**
     * 空指针异常
     */
    public class NullPointerException {
        public static void main(String[] args) {
            // 创建一个Student对象,将其赋值为bull
            Student student = new Student();
            student = null ;
    
            student.method();
        }
    }
    
    class Student {
    
        public void method() {
            System.out.println("method.....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    9.2.3 ArithmeticException 运算条件异常

    • 当出现错误的运算条件时抛出该异常
    /**
     * 运算条件异常
     */
    public class ArithmeticException {
        public static void main(String[] args) {
            int a = 0 ;
            int b = 1 ;
            System.out.println(b / a);  // 众所周知,0是不能作为除数的
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    ps:

    • 在除法算式中,除号后面的数叫做除数,除号前面的数叫做被除数。 如:6÷2=3,其中除号后面的2就是除数,6为被除数

    • 两个数之间相除有两种读法,分别读作“除”和“除以”。被除数读在前用“除以”表示,而除数读在前则用“除”表示。例如“15÷3”读作“15除以3”或读作“3除15”。

    9.2.4 ClassCastException 类转换异常

    • 在对没有子父类关系的类的对象进行转换时会出现
    public class ClassCastException {
        public static void main(String[] args) {
            // 使用多态向上转型的性质,创建一个String类对象
            Object obj = new String() ;
            // 因为Object类是ClassCastException类的父类,编译时不会报错
            ClassCastException cce = (ClassCastException) obj ;
    
            System.out.println(cce);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    9.3 异常处理机制一:try-catch-finally

    • 在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母是否为0,数据是否为空,输入的数据是不是数字等。这些我们都可以采用if-else语句进行判断,但是过多的if-else语句会导致代码臃肿,可读性差。因此采用异常处理机制。
    • Java异常处理

    Java采用的异常处理机制是将异常处理的代码集中到一起,与正常的代码分开,使程序变得简洁、优雅且易于维护

    public class Demo1 {
        public static void main(String[] args) {
            
            Demo1 d = new Demo1() ;
            d.methodA();
        }
    
        public void methodA() {
            
            methodB();
        }
    
        public void methodB() {
            
            methodC();
        }
    
        public void methodC() {
            System.out.println(1 / 0);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    • 为保证程序的正常执行,代码必须对可能出现的异常进行处理

      • 如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理,如果异常没有在调用者方法中处理,它会继续抛给调用方法的上层方法。这个过程将一直继续下去,直到异常被处理。这一过程被称为捕获(catch)异常

      • 如果一个异常被抛给了main()方法,且main()方法也没有处理,则程序中止。

      • 程序员通常只能处理Exception,对error也无能为力

    • try-catch-finally语句处理异常的格式:
    try {
    	可能产生异常的代码块
    } catch(异常类型1 变量名1) {
    	当异常类型1发生时的处置措施
    } catch(异常类型2 变量名2) {
    	当异常类型2发生时的处置措施
    }
    ......
    [finally {
    	无论是否发生异常都必定执行的代码
    }]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • try

      • 捕获异常的第一步就是将try{...} 语句块选定捕获异常的范围,将可能出现异常的代码放到try语句块中
    • catch(异常类型 变量名)

      • 在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随 一个或多个catch语句,用于处理可能产生的不同类型的异常对象
    • 如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可 以用其父类作为catch的参数。

    • 比 如 : 可 以 用 ArithmeticException 类 作 为 参 数 的 地 方 , 就 可 以 用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。 但不能是与ArithmeticException类无关的异常,如NullPointerException(catch 中的语句将不会执行)。

    • 捕获异常的有关信息: 与其它对象一样,可以访问一个异常对象的成员变量或调用它的 方法。

      • getMessage() :获取异常信息,返回字符串

    在这里插入图片描述

    • printStackTrace() :获取异常类名和异常信息,以及异常出 现在程序中的位置。无返回值

    在这里插入图片描述

    • finally

      • 捕获异常的最后一步是通过finally语句为异常处理提供一个 统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。

      • 不论在try代码块中是否发生了异常事件,catch语句是否执 行,catch语句是否有异常,catch语句中是否有return, finally块中的语句都会被执行。

      • finally语句是可选的

      • finally语句并不影响后面代码的执行

    • 示例:捕获到异常时的执行
    public class Demo2 {
        public static void main(String[] args) {
            try {
                System.out.println(1 / 0);
            } catch (ClassCastException e) {
                e.printStackTrace();
                System.out.println("ClassCastException...");
            } catch (ArithmeticException e) {
                e.printStackTrace();
                System.out.println("ArithmeticException...");
            } finally {
                System.out.println("finally....");
            }
            System.out.println("try-catch-finally语句块之外的代码");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述
    在这里插入图片描述

    • 没有捕获到异常时的执行

    在这里插入图片描述
    在这里插入图片描述

    • 注意:
    • 当我们声明了多个catch语句块时,如果catch中的异常类型没有子父类关系,则声明顺序无所谓;但是当异常类型存在子父类关系时,则要求子类一定声明在父类上面,否则会报错

    在这里插入图片描述

    • 前面使用的异常都是RuntimeException类或是它的子类,这些类的异常的特 点是:即使没有使用try和catch捕获,Java自己也能捕获,并且编译通过 ( 但运行时会发生异常使得程序运行终止 )。

    • 如果抛出的异常是IOException等类型的非运行时异常,则必须捕获,否则 编译错误。也就是说,我们必须处理编译时异常,将异常进行捕捉,转化为 运行时异常

    示例:

    • 把字符串转为日期类型时,会出现编译错误,不对这个错误进行处理是没办法运行程序的,所以说编译时异常是必须要处理的。
      在这里插入图片描述
    • IO异常
      在这里插入图片描述

    9.4 异常处理机制二:throws

    • 声明抛出异常是Java中处理异常的第二种方式

      • 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这 种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理, 而由该方法的调用者负责处理。

      • 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可 以是方法中产生的异常类型,也可以是它的父类。

    • 示例:
      在这里插入图片描述
      抛出异常
      在这里插入图片描述
    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class Demo3 {
        public static void main(String[] args) {
            Demo3 t = new Demo3();
            try {
                t.readFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public void readFile() throws IOException { // 将可能出现的异常抛给调用者处理
            FileInputStream in = new FileInputStream("test.txt");
            int b;
            b = in.read();
            while (b != -1) {
                System.out.print((char) b);
                b = in.read();
            }
            in.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    9.4.1 重写方法声明抛出异常的原则

    • 重写方法不能抛出比被重写方法范围更大的异常类型。在多态的情况下, 对methodA()方法的调用异常的捕获按父类声明的异常处理。

    在这里插入图片描述

    9.5 手动抛出异常

    • Java异常类对象除在程序执行过程中出现异常时由系统自动生成并 抛出,也可根据需要使用人工创建并抛出。

      • 首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运 行环境)。 IOException e = new IOException(); throw e;

      • 可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将 会产生语法错误: throw new String("want to throw");

    • 示例
    public class Demo4 {
        public static void main(String[] args) {
            new Demo4().method1();
        }
    
        public void method1() {
            System.out.println("手动抛出异常");
            throw new ClassCastException();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    • 示例
    public class Demo5 {
        public static void main(String[] args) {
            Student student = new Student();
            student.setAge(-20);
            System.out.println(student.getAge());
        }
    }
    
    class Student {
        private int age ;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            if (age > 0) {
                this.age = age;
            } else {
                throw new RuntimeException("年龄不能为负数");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    9.6 自定义异常类

    • 一般的,用户自定义异常类都是RuntimeException类的子类

    • 自定义异常类通常需要编写几个重载的构造方法

    • 自定义异常需要提供serialVersionUID

    • 自定义异常通过throw抛出

    • 自定义异常的名字非常重要,当异常出现时,可以根据名字判断异常类型

    • 案例:自定义异常类来对年龄的范围进行限制
      自定义异常类:AgeNegativeException
    public class AgeNegativeException extends RuntimeException {
    
        static final long serialVersionUID = 14725836945123L ;
    
        public AgeNegativeException() {
        }
    
        public AgeNegativeException(String message) {
            super(message);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

  • 相关阅读:
    @Autowired与@Resource区别
    Mock笔记
    护眼灯防蓝光什么意思?2022最新的护眼效果最好的led护眼灯推荐
    【WinForm详细教程一】WinForm中的窗体、Label、TextBox及Button控件、RadioButton和CheckBox、ListBox
    Linux SDIO-WiFi 协议栈
    【Pytorch with fastai】第 3 章 :数据伦理
    【数据结构】堆及堆排序的实现(C语言)
    商业化广告--体系学习--5--广告产品存在那些共性和区别
    了解JS中的混个对象“类”
    力扣刷题 day41:10-11
  • 原文地址:https://blog.csdn.net/weixin_45890113/article/details/126375994