第十章、 异常Exception

第十章、 异常Exception

10.1 异常的概念

  1. 引出异常:
    (1). 运行下面代码,看看有什么问题---->引出异常处理和异常处理机制
java 复制代码
package chapter10.exception_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class Exception01 {
    public static void main(String[] args) {
        int num1=10;
        int num2=0;
        //当除数为0时,就会抛出异常:ArithmeticException,当抛出异常后,程序就退出了,不再执行下面的代码了
        //问题来了:当一个程序很大的时候,只是出现了一点小bug,不影响整个程序运行的时候,如果因为这个小bug而停止了整个程序运行
        //是不划算的,所以就提出来异常处理解决这个问题
        int res=num1/num2;
        System.out.println("程序正常运行.....");
    }
}

(2). 对异常进行捕获,保证程序可以正常运行

将可能会出现的代码块-->选中-->快捷键ctrl+alt+t-->选中try-catch/直接按6

java 复制代码
package chapter10.exception_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class Exception01 {
    public static void main(String[] args) {
        int num1=10;
        int num2=0;
        //当除数为0时,就会抛出异常:ArithmeticException,当抛出异常后,程序就退出了,不再执行下面的代码了
        //问题来了:当一个程序很大的时候,只是出现了一点小bug,不影响整个程序运行的时候,如果因为这个小bug而停止了整个程序运行
        //是不划算的,所以就提出来异常处理解决这个问题
        try {
            int res=num1/num2;
        } catch (Exception e) {
            e.printStackTrace();//抛出异常
            System.out.println(e.getMessage());//输出异常信息
        }
        System.out.println("程序正常运行.....");
    }
}
/*
/ by zero
程序正常运行.....
*/
  1. 异常基本介绍
    (1). 基本概念
    Java语言中,将程序执行中发送不正常的情况称为"异常"。(开发过程中的语法错误和逻辑错误不是异常)
    (2). 执行过程中所发送的异常事件可分为两类
    ① Error(错误):Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。如比:StackOverflowError[栈溢出]和OOM(out of memory内存不足),Error是严重错误,程序就崩溃。
    ② Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。比如空指针访问,试图读取不存在的文件,网络连接中断等等,Exception分为两大类:运行时异常[程序运行时,发送的异常]和编译时异常[编程时,编译器检测出的异常]

10.2 异常体系图(重点)

  1. 异常体系图,体系了继承和实现关系(简易版)

    在IDEA中输入关键字Throwable后,ctr+b查看源码,然后直接右键->图表->显示图表。

    选中Throwable,ctrl+alt+b可以添加子类或者右键显示实现就可以添加;ctrl+alt+b后直接按字母进行搜索即可出现搜索框。

  2. 异常体系图(完整版)


  1. 异常体系图的小结
    (1). 异常分为两大类,运行时异常和编译时异常
    (2). 运行时异常(编译器检测不出来),编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。Java.lang.RuntimeException类及它的子类都是运行时异常。
    (3). 对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率可以产生影响。
    (4). 编译时异常,是编译器要求必须处置的异常。比如:读取文件时,文件不存在,这就是编译器异常,必须处理才可执行。

10.3 常见的异常

  1. 常见的运行时异常
    (1). NullPointerException空指针异常
    (2). ArithmeticException数字运算异常
    (3). ArrayIndexOutOfBoundsException数组下标越界异常
    (4). ClassCastException类型转换异常
    (5). NumberFormatException数字格式不正常异常[]

(1). NullPointerException空指针异常

当应用程序试图在需要对象的地方使用null时,抛出异常。

java 复制代码
package chapter10.exception_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class NullPointerException_ {
    public static void main(String[] args) {
        String string=null;
        System.out.println(string.length());
    }
}
/*
Exception in thread "main" java.lang.NullPointerException
   at chapter10.exception_.NullPointerException_.main(NullPointerException_.java:10)
 */

(2). ArithmeticException数字运算异常

当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。

(3). ArrayIndexOutOfBoundsException数组下标越界异常

用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。

java 复制代码
package chapter10.exception_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class ArrayIndexOutOfBoundsException_ {
    public static void main(String[] args) {
        int[] arr={1,2,3,4};
        for (int i = 0; i <= arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}
/*
1
2
3
4
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4
   at chapter10.exception_.ArrayIndexOutOfBoundsException_.main(ArrayIndexOutOfBoundsException_.java:11)
 */

(4). ClassCastException类型转换异常

当试图将对象强制转换为不是实例的子类时,抛出该异常。例如,一下代码将生成一个ClassCastException异常。

java 复制代码
package chapter10.exception_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class lassCastException_ {
    public static void main(String[] args) {
        A a=new B();//向上转型
        B b=(B)a;//向下转型
        C c=(C)a;//
    }
}

class A{}
class B extends A{}
class C extends A{}
/*
Exception in thread "main" java.lang.ClassCastException: class chapter10.exception_.B cannot be cast to class
chapter10.exception_.C (chapter10.exception_.B and chapter10.exception_.C are in unnamed module of loader 'app')
   at chapter10.exception_.lassCastException_.main(lassCastException_.java:11)
 */

(5). NumberFormatException数字格式不正常异常[]

当应用程序试图将字符串转成一种数值类型,但该字符串不能转换为设当格式时,抛出该异常=> 使用异常我们可以确保输入是满足条件数字。

java 复制代码
package chapter10.exception_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class NumberFormatException_ {
    public static void main(String[] args) {
        String name="hello";
        int num=Integer.parseInt(name);
    }
}
/*
Exception in thread "main" java.lang.NumberFormatException: For input string: "hello"
   at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
   at java.base/java.lang.Integer.parseInt(Integer.java:652)
   at java.base/java.lang.Integer.parseInt(Integer.java:770)
   at chapter10.exception_.NumberFormatException_.main(NumberFormatException_.java:10)
 */
  1. 常见的编译异常

    编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译。

    (1). SQLException 操作数据库时,查询表可能发生异常

    (2). IOException 操作文件时,发生的异常

    (3). FileNotFoundException 当操作一个不存在的文件时,发生异常

    (4). ClassNotFoundException 加载类,而该类不存在时,发生异常

    (5). EOFException 操作文件,到文件末尾,发生异常

    (6). IllegalArgumentException 参数异常

  2. 判断下面代码是否正确,为什么?

10.4 异常处理概念

  1. 基本介绍

    异常处理就是当异常发生时,对异常处理的方式。

  2. 异常处理的方式

    (1). try-catch-finally

    程序员在代码中捕获发生的异常,自行处理

    (2). throws

    将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM。

  3. try-catch-finally处理机制

  4. throws处理机制

10.5 异常处理分类

10.5.1 try-catch方式处理异常

java提供try和catch块来处理异常。try块用于包含可能会出现错误的代码。Catch块用于处理try块中发生的异常。可以根据需要再程序中有多个数量的try...catch块。

  1. 基本语法
java 复制代码
try{
    //可疑代码
    //将异常生成对应的异常对象,传递给catch块
}catch (异常){
    //对异常的处理
}
//如果没有finally,语法是可以通过的
  1. try-catch方式处理异常-注意事项
    (1). 如果异常发生了,则异常发生后面的代码不会执行,直接进入到代码块。
    (2). 如果异常没有发生,则顺序执行try的代码块,不会进入到catch。
    (3). 如果不希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等),在后面加上finally{}。
java 复制代码
try{
    //可疑代码
    //将异常生成对应的异常对象,传递给catch块
}catch (异常){
    //对异常的处理
}finally {
    //释放资源等..
}

如下代码,例子:TryCatchDetail01

java 复制代码
package chapter10.try_;

import java.util.Scanner;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class TryCatchDetail01 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        String str=scanner.next();
        try {
            int a=Integer.parseInt(str);//将输入的字符串类型的数字转换为整数类型
            System.out.println("数字:"+a);//如果输入不是整数,这句话就不会执行
        } catch (NumberFormatException e) {
            System.out.println("异常信息:"+e.getMessage());
        }finally {
            scanner.close();//不论是否发生异常都关闭资源
        }
    }
}
/*
输入:123
数字:123
输入:fa1
异常信息:For input string: "fa1"
 */

(4). 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException在前),如果发生异常,只会匹配一个catch。

java 复制代码
try {
}catch (NullPointerException){
}catch (Exception){
}finally {
}

例子TryCatchDetail02

java 复制代码
package chapter10.try_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class TryCatchDetail02 {
    public static void main(String[] args) {
        try {
            Person person = new Person();
//            person=null;//NullPointerException
            person.say();
            int i=10/0;//ArithmeticException
            //要求子类异常要写在父类异常前面,不然会报错
        } catch (NullPointerException e){
            System.out.println("空指针异常"+e.getMessage());
        } catch (Exception e) {
            System.out.println("算术异常"+e.getMessage());
        }finally {//这里可以没有
            System.out.println("有没有异常都执行....");
        }
    }
}

class Person{
    public void say(){}
}
/*
算术异常/ by zero
有没有异常都执行....
 */

(5). 可以进行try-finally配合使用,这种用法相等于没有捕获异常,因此程序会直接崩掉。应用场景,就是执行一端代码,不管是否发生异常,都必须执行某个业务逻辑。

java 复制代码
try{
    //代码
}final {//总是执行
}

例子:TryCatchDetail03

java 复制代码
package chapter10.try_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class TryCatchDetail03 {
    public static void main(String[] args) {
        try {
            int n1=10;
            int n2=0;
            System.out.println(n1/n2);
        } finally {
            System.out.println("执行了finally...");
        }
        System.out.println("程序继续执行...");
    }
}
/*
执行了finally...
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at chapter10.try_.TryCatchDetail03.main(TryCatchDetail03.java:12)
 */
  1. 练习
    (1). 判断下面代码输出是什么?
java 复制代码
package chapter10.try_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class TryCatchExercise01 {
    public static void main(String[] args) {
        System.out.println(method());//4
    }
    public static int method(){
        try {
            String[] strings=new String[3];
            if(strings[1].equals("mark")){//NullPointerException
                System.out.println(strings[1]);
            }else {
                strings[3]="smith";
            }
            return 1;
        } catch (NullPointerException e) {
            return 2;
        }catch (ArrayIndexOutOfBoundsException e){
            return 3;
        }finally {
            return 4;
        }
    }
}

(2). 判断下面代码输出是什么?

java 复制代码
package chapter10.try_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class TryCatchExercise02 {
    public static void main(String[] args) {
        System.out.println(method());//4
    }
    public static int method(){
        int i=1;
        i++;
        try {
            String[] strings=new String[3];
            if(strings[1].equals("mark")){//NullPointerException
                System.out.println(strings[1]);
            }else {
                strings[3]="smith";
            }
            return 1;
        } catch (ArrayIndexOutOfBoundsException e) {
            return 2;
        }catch (NullPointerException e){
            return ++i;
        }finally {//必须执行
            return ++i;
        }

    }
}

(3). 判断下面代码输出是什么?

java 复制代码
package chapter10.try_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class TryCatchExercise03 {
    public static void main(String[] args) {
        System.out.println(method());
        //i=4
        //3
    }
    public static int method(){
        int i=1;
        i++;
        try {
            String[] strings=new String[3];
            if(strings[1].equals("mark")){//NullPointerException
                System.out.println(strings[1]);
            }else {
                strings[3]="smith";
            }
            return 1;
        } catch (ArrayIndexOutOfBoundsException e) {
            return 2;
        }catch (NullPointerException e){
            return ++i;//i=3=>保存临时变量temp=3
        }finally {//必须执行
            ++i;//4
            System.out.println("i="+i);
        }
    }
}

(4). 如果用户输入的不是一个整数,就提示他反复输入,知道输入一个整数为止。(用异常来做)。(肯定要循环的,不然try块 和catch块不管有没有问题,都只会执行一次)

java 复制代码
package chapter10.try_;

import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class TryCatchExercise04 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int input = 0;
        boolean validInput = false;

        while (!validInput) {
            try {
                System.out.print("请输入一个整数: ");
                input = scanner.nextInt();
                validInput = true; // 如果能成功获取整数则退出循环
            } catch (InputMismatchException e) {
                System.out.println("对不起,你输入的不是整数,请重新输入~~~~");
                scanner.nextLine(); // 清除缓冲区的非整数输入
            }
        }

        System.out.println("你输入的整数是: " + input);
        scanner.close();
    }
}
/*
请输入一个整数: 123f
对不起,你输入的不是整数,请重新输入~~~~
请输入一个整数: fa
对不起,你输入的不是整数,请重新输入~~~~
请输入一个整数: 12
你输入的整数是: 12
 */
  1. try-catch-finally执行顺序小结
    (1). 如果没有出现异常,则执行try块中所有语句,不执行catch块中语句,如果有finally,最后还需执行finally里面的语句。
    (2). 如果出现异常,则try块中异常发生后,try块剩下的语句不再执行,将执行catch块中的语句,如果有finally,最后还需执行finally里面的语句。

10.5.2 Throws异常处理

  1. 基本介绍
    (1). 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如果处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
    (2). 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
java 复制代码
package chapter10.throws_;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class Throws01 {
    public static void main(String[] args) {

    }
    public void f2() throws FileNotFoundException {
        //1. 这里的异常是一个FileNotFoundException,属于编译异常 
        //2. 这里可以使用try-catch-finally
        //3. 也可以使用throws,抛出异常,让调用f2方法的调用者(方法)处理
        //4. throws后面的异常类型可以是具体产生的异常,也可以是父类异常
        //5. throws后面可以写多个异常,用逗号分隔。即异常列表。若父类异常都是一样的可以用父类异常替代
        FileInputStream fis=new FileInputStream("D://a.test");
    }
}
  1. throws注意事项和使用细节
    (1). 对应编译异常,程序中必须处理,比如:try-catch-或者throws。
    (2). 对于运行时异常,程序中如果没有处理,默认就是throws的方式处理
    (3). 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型。
    (4). 在throws过程中,如果有方法try-catch,相当于处理异常,就可以不必throws。
java 复制代码
package chapter10.throws_;

import java.io.FileNotFoundException;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class ThrowsDetail {
    public static void main(String[] args) {

    }
    public void f1(){
        //1.这里调用f2()会报错,因为f2抛出了一个编译异常
        //2.f1作为f2的调用者,必须处理这个编译异常
        //3.要么使用try-catch-finally处理,或者继续throws 这个编译异常
        f2();
    }
    public void f2() throws FileNotFoundException {}


    public void f3(){
        //1.这里调用f4()不会报错,因为f4抛出了一个运行异常
        //2.在Java中,并不要求程序员显示处理运行异常,因为有默认处理机制
        f4();
    }
    public void f4() throws ArithmeticException{}

}


class Father{
    public void method() throws RuntimeException{}
}
class Son extends Father{
    //(3). 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,
    // 所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型。
    @Override
    public void method() throws NullPointerException{}
}

10.6 自定义异常

  1. 基本概念

    当程序中出现了某些"错误",但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。

  2. 自定义异常的步骤

    (1). 定义类:自定义异常类名(程序员自己写)继承Exception或RuntimeException

    (2). 如果继承Exception,属于编译异常

    (3). 如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)

  3. 自定义异常的应用案例CustomException.java

    当接收Person对象年龄时,要求范围在18-120之间,否则抛出一个自定义异常(要求 继承RuntimeException),并给出提示信息。

java 复制代码
package chapter10.customexception_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class CustomException01 {
    public static void main(String[] args) {
        int age=12;
        if(!(age>=18 && age<=120)){
            throw new AgeException("年龄需要在18-120之间");
        }
        System.out.println("你的年龄范围正确");
    }
}

//1.一般情况下,都是自定义异常是继承RuntimeException
//2.即把自定义异常做成 运行时异常,好处是,可以使用默认的处理机制(比较方便)
class AgeException extends RuntimeException{
    public AgeException(String message) {
        super(message);
    }
}
/*
Exception in thread "main" chapter10.customexception_.AgeException: 年龄需要在18-120之间
	at chapter10.customexception_.CustomException01.main(CustomException01.java:11)
 */

10.7 throw和throws的对比

  1. throw和throws的区别
意义 位置 后面跟的东西
throws 异常处理的一种方式 方法声明处 异常类型
throws 手动生成异常对象的关键字 方法体中 异常对象
java 复制代码
package chapter10.customexception_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class ThrowException {
    public static void main(String[] args) {
        try {
            methodA();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        methodB();
    }
    /*
    1.首先调用methodA方法,进入catch块:输出进入方法A,抛出异常给对象e,再进入finally块:输出用A方法的finally,最后main方法的e.getMessage()
    2.调用methodB方法,进入catch块:输出进入方法B,再进入finally块:输出调用B方法的finally
    3.输出如下:
    进入方法A
    用A方法的finally
    制造异常
    进入方法B
    调用B方法的finally
     */
    static void methodA(){
        try {
            System.out.println("进入方法A");
            throw new RuntimeException("制造异常");
        } finally {
            System.out.println("用A方法的finally");
        }
    }
    static void methodB(){
        try {
            System.out.println("进入方法B");//4
            return;
        } finally {
            System.out.println("调用B方法的finally");//5
        }
    }
}

10.8 本章作业

  1. 编程题
    (1). 编写应用程序EcmDef.java,接收命令行的两个参数(整数),计算两数相除。
    (2). 计算两个数相除,要求使用方法cal(int n1,int n2)
    (3). 对数据格式不正确,缺少命令行参数、除0进行异常处理。
    解析:什么是命令行参数?其实就是args的参数。前面讲过怎么过去args参数。
java 复制代码
package chapter10.task_;

import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task01 {
    public static void main(String[] args) {
        try {
            // 检查是否提供了足够的命令行参数
            if (args.length != 2) {
                throw new IllegalArgumentException("需要输入两个整数作为命令行参数");
            }

            // 将命令行参数转换为整数
            int n1 = Integer.parseInt(args[0]);
            int n2 = Integer.parseInt(args[1]);

            // 计算并输出结果
            double result = cal(n1, n2);
            System.out.println("两数相除的结果是:" + result);
        } catch (NumberFormatException e) {
            System.out.println("输入的参数格式不正确,请输入整数。");
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("除数不能为零。");
        }
    }

    public static double cal(int n1, int n2) {
        if (n2 == 0) {
            throw new ArithmeticException("除数不能为零。");
        }
        return (double) n1 / n2;
    }
}
//输出:两数相除的结果是:2.0
  1. 判断下面代码是否会发生异常,如果会,是哪种异常?如果不会,则打印结果是什么?
java 复制代码
package chapter10.task_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task02 {
    public static void main(String[] args) {
        if(args[4].equals("john")){//可能发生NullPointerException
            System.out.println("hello");
        }else{
            System.out.println("hi");
        }
        Object obj=args[2];
        Integer i =(Integer) obj;//一定会发生ClassCasException
    }
}
  1. 写出下面代码输出结果
java 复制代码
package chapter10.task_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task03 {
    public static void main(String[] args) {
        try {
            func();
            System.out.println("a");
        } catch (Exception e) {
            System.out.println("c");//2
        }
        System.out.println("d");//3
    }
    public static void func(){
        try {
            throw new RuntimeException();
        }finally {
            System.out.println("b");//1
        }
    }
}
  1. 写出下面代码输出结果
java 复制代码
package chapter10.task_;

/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task04 {
    public static void main(String[] args) {
        try {
            showExce();
            System.out.println("a");
        } catch (Exception e) {
            System.out.println("b");//1
        } finally {
            System.out.println("c");//2
        }
        System.out.println("d");//3
    }
    public static void showExce() throws Exception{
        throw new Exception();
    }
}
相关推荐
陶然同学1 分钟前
【小程序】wxss与rpx单位以及全局样式和局部样式
java·微信小程序·小程序
@Java小牛马2 分钟前
排序算法原理及其实现
java·数据结构·算法·排序算法
sensen_kiss9 分钟前
CPT203 Software Engineering 软件工程 Pt.1 概论和软件过程(中英双语)
学习·软件工程
vvw&10 分钟前
如何在 Ubuntu 22.04 上安装并开始使用 RabbitMQ
java·linux·运维·服务器·spring·ubuntu·rabbitmq
美式小田10 分钟前
Cadence学习笔记 16 HDMI接口布局
笔记·嵌入式硬件·学习·cadence
被猫枕的咸鱼25 分钟前
【免费分享】mysql笔记,涵盖查询、缓存、存储过程、索引,优化。
笔记·mysql·缓存
万琛40 分钟前
【Java-tesseract】OCR图片文本识别
java·ocr
励志成为大佬的小杨44 分钟前
c语言中的枚举类型
java·c语言·前端
yava_free1 小时前
指定Bean加载顺序的能力
java·开发语言
yan_baby_liu1 小时前
1.business english--build rapport
笔记