java异常

目录

1.异常

1.1异常的概述

1.2异常的体系

1.3 在jvm中默认处理异常的机制

2. 处理异常的方式

2.1有两大类处理异常的方式:

2.2 异常捕获的第一种格式

2.3 异常捕获的第一种格式的多种异常情况

2.4 异常捕获的第二种格式

2.5 异常处理的第三种格式

3. 继承体系中的常用方法

4.自定义异常

4.1 throw关键字

4.2 throws关键字

4.3 throw和throws的比较

4.4 自定义异常类


1.异常

1.1异常的概述

  • 在java程序《运行》过程中,出现的不正常情况,出现的错误,称为异常

  • 异常就是一个对象,描述那些不符合生活正常情况的异常情况,包含了这些情况的原因、类型、描述以及位置,这些内容都封装到异常对象中。

  • 异常也是一种处理异常情况的机制,可以进行跳转、捕获以及结束程序,提供了程序退出的安全通道

  • image-20230212220608181

1.2异常的体系

  • Throwable:可抛出的,是异常体系的顶层父类,其它的异常或者错误都是Throwable的子类类型,只有Throwable的体系类型,才可以使用异常的处理机制

  • Error:错误,是Throwable的子类,用于描述那些无法捕获和处理的错误情况,属于非常严重的错误,StackOverflowError

  • Exception:异常,是Throwable的子类,用于描述那些可以捕获和处理的例外情况,属于不太严重的错误ArrayIndexOutOfBoundsException,NullPointerException

  • RuntimeException:运行时异常,是Exception的特殊的子类,在编译阶段不做检查的一个异常

    这种异常我们不需要处理,由虚拟机掌管,比如NullPointerException,ArrayIndexOutOfBoundsException

  • 体系图:

    image-20230212222526711

1.3 在jvm中默认处理异常的机制

  • 演示代码:

/**
 * 在jvm中 默认处理异常的机制
 */
public class Simple01 {
​
    public static void main(String[] args) {
        test1();
    }
​
    public static void test1() {
        test2();
    }
​
    public static void test2() {
        test3();
    }
​
    public static void test3() {
        int i = 1 / 0;
        System.out.println(i);
    }
}
  • 在代码的某个位置,出现了和正常情况不同的情况,就将异常情况封装到一个异常对象中。

  • 将异常对象抛给调用该方法的方法,A调用B, B有问题就把异常抛给A。

  • 某个方法接收到底层方法抛上来的异常,也没有办法自己处理,继续向上抛出,最终抛给main方法,main方法也没有办法处理,抛给调用自己的jvm虚拟机

  • Jvm虚拟机是我们手动调用的,只能将异常对象的所有信息,通过错误信息打印出来,结束jvm虚拟机

  • 总结,jvm默认处理的方式:【一层一层向上抛,jvm接收到之后结束自己】

2. 处理异常的方式

2.1有两大类处理异常的方式:

  • 异常的声明:某个方法有编译时异常,编译就会无法通过,需要在异常所在的方法声明上,声明该方法可能出现的编译时异常

    public  static void  test () throws FileNotFoundException 
    {
    FileInputStream fileInputStream = new FileInputStream("/Users/lihongyan/Desktop/未命名.html");
     }
    ​
    JDK11新增方式
    Path path = Paths.get("/Users/lihongyan/Desktop/未命名.html");
    String data = Files.readString(path);
    System.out.println(data);
  • 异常的捕获:出现异常之后,可以通过某些格式来捕获,可以让程序在出现异常之后,继续运行,可以定义自己处理异常的逻辑。

  • 捕获处理异常的代码格式:

    • try...catch

    • try...catch...finally

    • try...finally(无法捕获处理异常)

2.2 异常捕获的第一种格式

  • 格式

    • try   {
               可能发生异常的代码
            } catch(可能出现异常的类型 标识符) {
                      这种异常出现之后的处理方式
            }
  • try:试一试

    • try语句块中,是可能会运行失败的代码,try语句是用于对异常进行检测

  • catch:抓住、捕获

    • 抓住try语句中出现的异常,并且定义异常处理的方式

  • 运行机制:

    • 运行try语句中的代码

    • 如果没有发生任何异常,那么不再运行catch块中的内容

    • 如果发生了catch中声明的异常,那么就会被捕获到这个异常,执行catch块中的内容(try中如果发生了异常,try中,该语句后面的代码都无法执行了,直接跳到catch中)

    • 如果发生了catch中没有声明的异常,那么就无法捕获该异常,该异常的处理就使用jvm的默认处理方式

2.3 异常捕获的第一种格式的多种异常情况

  • 在一段代码中,可能出现多种异常(虽然一次运行只能出现一个异常,但是出现哪个异常我们是不清楚的),所以要准备多种异常情况的处理机制。

  • 格式:

  • try {
            可能出现异常的代码
    } catch (异常类型1  异常对象名1) {
        异常类型1出现之后的处理办法
    } catch (异常类型2  异常对象名2) {
        异常类型2出现之后的处理办法
    }
    ....
    } catch (异常类型n 异常对象名n) {
        异常类型n出现之后的处理办法
    }
  • 执行流程:

    • 执行try中的内容,如果没有异常,try...catch语句直接结束

    • 如果有异常,那么就在发生异常的代码位置直接跳转到catch块中,try中后面的代码就不再继续运行了

    • 继续匹配各个catch块中的异常类型,从上到下,一旦匹配到某个catch声明的异常类型,就直接执行该catch块的处理方式。处理完成之后,try...catch语句就直接结束了,不会再去匹配后面其他的catch块的异常类型

  • 代码示例:

/**
 * 异常捕获的第一种格式的多种异常情况
 */
public class Simple02 {
​
    public static void main(String[] args) {
        test();
    }
​
    public static void test() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请录入一个除数");
        try {
            int i = 100 / sc.nextInt();
            System.out.println(i);
            int[] arr = {1, 3, 5, 7, 9};
            System.out.println(arr[5]);
        }
          catch (ArithmeticException a) {
           System.out.println("出现数学运算异常");
        } catch ( ArrayIndexOutOfBoundsException a) {
           System.out.println("出现索引越界异常");
        }
        // catch (ArithmeticException  | ArrayIndexOutOfBoundsException a) {
        //     System.out.println(a.getMessage());
        // }
    }
}
​
  • 注意事项:

    • 如果在各个catch块中,出现了子父类的异常类型,那么子类异常的catch块,必须在父类异常catch块的上面,因为从上到下匹配方式,如果父类的catch块在上面,下面的catch块就没有出现的意义了。

    • 在jdk1.7之后,可以对异常类型进行逻辑的或运算,使用|表示,多种异常类型,可以使用相同的处理方式:

  • catch(异常类型1 | 异常类型2  异常对象名称) {
                异常类型1和2的共同处理方式a.getMessage()
    }

2.4 异常捕获的第二种格式

  • 格式:

  • try {
            可能发生异常的代码
          } 
      catch (可能发生的异常类型  异常对象名称) {
             当前异常类型的处理方式
    }  finally {
           一定要执行的代码
    }
  • finally:一定要执行的代码

    • 如果把某句代码放在try中,可能在这句话前面有异常,那么这句话就无法执行;如果把某句代码放在catch中,有可能try中没有异常,就无法执行这句话;如果把某句代码放在try...catch之后,可能有未捕获的异常,那么这句代码也无法执行。

    • finally:也是一个代码块,在这个代码块中的代码,一定会执行,无论上面描述的哪种情况,都会执行。

    • 作用:一般使用关闭资源

    • -示例代码:

/**
 * 异常捕获的第二种格式
 */
public class Simple03 {
​
    public static void main(String[] args) {
        test();
    }
​
    public static void test() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请录入一个除数");
        try {
            int i = 100 / sc.nextInt();
            System.out.println(i);
            int[] arr = {1, 3, 5, 7, 9};
            System.out.println(arr[5]);
        }
         catch (ArithmeticException  | ArrayIndexOutOfBoundsException a) {
             System.out.println(a.getMessage());
         } finally {
            System.out.println("我一定要执行");
        }
    }
}

2.5 异常处理的第三种格式

  • 格式:

  • try {
            可能发生异常的代码
    } finally {
        一定要执行的代码
    }
  • 作用:

    • 第三种格式无法捕获和处理异常,一旦发生任何异常,仍然会按照默认的处理方式,一层一层向上抛出,到达jvm,结束虚拟机

    • 无论try中的语句是否发生异常,finally中的代码都一定有执行的机会

    • 如果有两句代码,都需要有执行的机会,不希望第一句的成功与否影响到第二句的执行机会,那么就把这两句代码分别放在try和finally中,就是try中你报你的错,我finally中代码该咋执行咋执行。

  • 代码示例:

import java.util.Scanner;
​
/**
 * 异常处理的第三种格式
 */
public class Simple04 {
    public static void main(String[] args) {
        try {
            System.out.println("输入一个除数");
            System.out.println(1 / new Scanner(System.in).nextInt());
        } finally {
            System.out.println("一定有机会执行的代码");
        }
    }
}

3. 继承体系中的常用方法

  • 在异常的继承体系中,所有的方法定义在了Throwable这个顶层父类中,子类中几乎没有什么特有方法

  • Throwable中的构造方法: Throwable():创建一个没有任何参数的异常对象 Throwable(String message):创建一个带有指定消息的异常对象 Throwable(Throwable cause):创建一个有原因异常的异常对象

  • 常用成员方法: getMessage():获取异常的详细信息 toString():获取异常对象的详细信息 printStackTrace():打印异常的调用栈轨迹(有关异常的方法调用路径)

  • 代码示例:

import java.util.Scanner;
​
/**
 * 继承体系中的常用方法
 */
public class Simple05 {
    public static void main(String[] args) {
        test();
    }
    private static void test() {
        try {
            System.out.println("输入一个除数");
            System.out.println(1 / new Scanner(System.in).nextInt());
        } catch (ArithmeticException ae) {   // 这里可以介绍一下exception异常
            System.out.println(ae.getMessage());//获取当前异常对象的消息字符串
            System.out.println(ae.toString());//获取当前异常对象的字符串描述
            System.out.println("--------------------------");
            ae.printStackTrace();//获取当前异常对象的方法调用路径
        }
    }
}

4.自定义异常

4.1 throw关键字

  • throw:抛出,用于抛出一个异常对象

  • 异常是一个对象,当程序运行到某种情况时,程序员认为这种情况和现实生活不符合,就把当前的对于情况的描述,封装到一个异常对象中,通过throw关键字将异常对象进行抛出。

  • 作用: 创建一个异常对象,使用throw关键字抛出,实现了程序的结束或者跳转

  • 说明:

  • 如果抛出的是运行时异常,在编译阶段就相当于没有异常,可以不处理这个异常
    如果抛出的是编译时异常,那么这个异常必须使用异常处理的方式处理,才能编译成功
  • 代码示例

public class Simple06 {
    public static void main(String[] args) {
        test();
    }
    private static void test() {
        Person person = new Person();
        person.setName("小明");
        try {
            person.setAge(-20);
        }catch ( RuntimeException re) {
            System.out.println(re.getMessage());
        }
        System.out.println(person);
    }
}
​
public class Person {
    private  String name;
    private Integer age;
​
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public Person() {
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public Integer getAge() {
        return age;
    }
​
    public void setAge(Integer age) {
        if (age <= 0) {
            // 年龄小于0,这种情况不符合生活正常情况,就将这种情况封装成异常对象
            // 如果抛出的是运行时异常,在编译阶段就相当于没有异常,可以不处理这个异常
            // RuntimeException re = new RuntimeException();
            // throw re;//将异常对象
           throw new RuntimeException("年龄不能为负值");
​
        }
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
 

4.2 throws关键字

  • throws:抛出,用于声明一个异常类型

  • 在某个方法中,有一些编译时异常,没有给出处理的方案,没有捕获这个异常,没有处理这个异常,就说明这个方法是一个有问题的方法。为了让调用者在调用时,可以考虑到处理这个异常,所必须在当前方法的声明上,声明这个异常。

  • 声明格式:

    修饰符 返回值类型 方法名称(参数列表) throws 异常类型1, 异常类型2,... {
            可能出现异常的代码
    }

  • 注意事项:

    • 如果抛出的是一个运行时异常,那么就相当于没有抛出异常,这种异常也不需要在方法上声明;声明了一个运行时异常,也相当于没有做任何声明

    • 如果抛出的是一个编译时异常,那么就必须进行声明或者捕获;如果声明了一个编译时异常,将来调用这个方法时,也相当于有一个声明的异常。

    • 在声明异常的时候,尽量声明<小>的异常、尽量声明<少>的异常

    • 一个方法暴露太多异常,别人不敢调用你了

    • 代码示例:

public class Simple07 {
    public static void main(String[] args) {
        test();
    }
    private static void test() {
        Person person = new Person();
        person.setName("小明");
        try {
            person.setAge(-20);
        }catch ( Exception re) {
            System.out.println(re.getMessage());
        }
        System.out.println(person);
    }
}
​
public class Person {
    private  String name;
    private Integer age;
​
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public Person() {
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public Integer getAge() {
        return age;
    }
​
    public void setAge(Integer age) throws Exception {
        if (age <= 0) {
            // 年龄小于0,这种情况不符合生活正常情况,就将这种情况封装成异常对象
            // 创建编译时 异常
           throw new Exception("年龄不能为负值");
​
        }
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
​

4.3 throw和throws的比较

  • throw是对异常对象的抛出,throws是对异常类型的声明

  • throw是对异常对象实实在在的抛出,一旦使用了throw关键字,就一定有一个异常对象出现;

    throws是对可能出现的异常类型的声明,即使声明了异常类型,在该方法中,也可能不出现任何异常。

  • throw后面只能跟一个异常对象;

    throws可以跟很多个异常类型

4.4 自定义异常类

public class Simple08 {
    public static void main(String[] args) {
        test1();
        test2();
    try {
         test3();
     } catch (ExceptionDemo2 e) {
         System.out.println(e.getMessage());
     }
    }
    private static void test1()  throws  ExceptionDemo1 {
        String str = null;
        System.out.println(str.length());
    }
    private static void test2()  throws ExceptionDemo2 {
        String str = null;
        System.out.println(str.length());
    }
    private static void test3() {
        throw new ExceptionDemo2("异常");
    }
}
​
class ExceptionDemo1 extends  RuntimeException {
​
}
class ExceptionDemo2 extends  Exception {
    public ExceptionDemo2(String message) {
        super(message);
    }
​
    public ExceptionDemo2() {
    }
}

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

White-Camellia

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值