异常体系结构和分类

异常

异常的体系结构和分类

1.什么是异常?

异常就是程序出现了不正常的情况

注意: 语法错误不算在异常体系中

2.异常的结构体系

在这里插入图片描述

Error:严重问题,通过代码无法处理

比如:内存溢出

Exception:称为异常类,他表示程序本身可以处理的问题

  • RuntimeException及其子类:运行时异常.(空指针异常,数组索引越界异常)
  • 除RuntimeException之外所有的异常:编译器必须处理的,否则程序不能通过编译(比如:日期格式化异常)

在这里插入图片描述

3.编译时异常和运行时异常的区别
  • 编译时异常
    • 都是Exception类及其子类
    • 必须显式(手动处理),否则程序就会发生错误,无法通过编译
  • 运行时异常
    • 都是RuntimeException类及其子类
    • 无需显式处理(手动处理),也可以和编译时异常一样处理
  • 图示

在这里插入图片描述

JVM默认处理异常的方式

1.如果程序出现了问题,我们没有处理,最终jvm虚拟机会做默认的处理,处理方式有两个步骤

  • 把异常的名字,异常原因,异常出现的位置等信息输出在控制台

  • 停止程序的运行

在这里插入图片描述

public class ExceptionDemo2 {
    /*
    * 在遇到异常的时候,jvm虚拟机会做那些事?
    * 1.会把异常的名字,异常出现的原因,异常的位置带给我们
    * 2.会让程序停止在异常出现的位置
    * */
    /*
    * 当异常出现时候,首先看的时本程序中是否有异常的处理方法
    * 如果没有,要看这个方法的调用者,是否处理了这个异常
    * 如果还没有,最终这个异常会交给虚拟机处理
    * */

    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        // 可以看出程序在异常之前都能正常执行,
        System.out.println("黑马666");
        
        
        //在这里编译时期没有错,但是运行时候会报错,
        // 那么就会在这里创建一个异常对象
        // new ArrayIndexOutOfBoundsException();
        System.out.println(arr[10]); 
        
        
        
        //在执行的遇到异常,程序会停止,后边的内容不再执行
        System.out.println("黑马牛皮,我是黑马程序员");
    }
}

throws方式处理异常

定义格式

public void 方法() throws 异常类名{
    
}
  • 示例代码1
public class ExceptionDemo3 {
// 格式 public void 方法() throws 异常类名{}
    // throws ParseException,是告诉调用者,你调用我,有可能出现这样的异常
    // 把问题丢给了调用或者处理,调用者不处理,最终会交给虚拟机处理
    public static void main(String[] args) throws ParseException {
        String dateStr = "2011-11-11 12:12:12";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //这里出现了一个ParseException异常
        simpleDateFormat.parse(dateStr);
        
    }
}

throws方式处理异常-注意事项

简单来说:编译时的异常,必须声明,谁调用谁处理,最多让jvm来处理,运行时异常可以不声明

throw抛出异常

1.格式

throw new 异常();

2.注意

这个格式是在方法内的,表示当前代码手动抛出一个异常,下面的代码无法再执行了

3.抛出异常处理的意义

1.在方法中如果传递的参数有误,没有继续运行下去的必要了,采取抛出处理,表示该方法结束

2.告诉方法调用者出现了问题

4.throws和throw的区别

throws

用在方法声明的后面,跟的是异常类名

表示的是声明异常,调用该方法有可能会出现这样的异常

可以声明多个异常

throw

用在方法体内,跟的是异常对象名

表示手动抛出异常对象

只能声明一个异常

public class ExceptionDemo4 {
    public static void main(String[] args) {
        System.out.println("黑马");
        System.out.println("传智");
        System.out.println("培训");
        System.out.println("学习");
        // 在这里创建一个运行时的异常对象,并且没做处理
        // 下面的"开心"的字符串没有了打印的可能性,
        // 就会报错
        throw new RuntimeException();
        // System.out.println("开心"); //这行代码不会执行,我就先注释了
    }
}

public class ExceptionDemo5 {
    public static void main(String[] args) {

        method1();//调用方法的时候,如果输入不符合要求的值,我们就会接收到一个异常对象
                    // 我们需要自己处理这个异常

    }

    private static void method1() {
        int[] arr = {1, 2, 3, 4, 5};
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入索引值:");
        int index = sc.nextInt();
        if (index >= arr.length) {
            // 当index的值大于或等于数组长度的时候,我们手动创建了一个异常对象
            // 并抛给调用者一个异常
            // 此时我们并没有处理这个异常
            throw new ArrayIndexOutOfBoundsException();
        } else {
            System.out.println(arr[index]);
        }
    }
}

try-catch自己处理异常

  • 定义格式
try{
    可能出现的异常的代码段
}catch(异常类名 变量名){
    异常代码的处理代码
}
  • 执行流程
    • 程序从try里面的代码开始执行
    • 出现异常,就会跳转到对应的catch里面去执行
    • 执行完毕后,程序还可以继续往下执行
  • 示例代码
public class ExceptionDemo5 {
    public static void main(String[] args) {

        // 异常处理,把可能出现异常的代码加入到try里面,
        // 当出现异常的时候,用catch捕获并做处理
        try {
            method1();//调用方法的时候,如果输入不符合要求的值,我们就会接收到一个异常对象
                        // 我们需要自己处理这个异常
        }   catch (ArrayIndexOutOfBoundsException ex){
            System.out.println("亲,您的输入索引越界了");
        }
        // 当catch处理完捕获的对象的后,这行代码可以继续执行
        // 当然,如果没有对异常进行处理,这个代码
        System.out.println("还能继续执行这个");

    }

    private static void method1() {
        int[] arr = {1, 2, 3, 4, 5};
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入索引值:");
        int index = sc.nextInt();
        if (index >= arr.length) {
            // 当index的值大于或等于数组长度的时候,我们手动创建了一个异常对象
            // 并抛给调用者一个异常
            // 此时我们并没有处理这个异常
            throw new ArrayIndexOutOfBoundsException();
        } else {
            System.out.println(arr[index]);
        }
    }
}

try-catch常见问题

1.如果try中没有遇到问题,怎么执行

会把try中所有代码全部执行完毕,不会执行catch里面的代码

2.如果try中遇到问题,try下面的代码还会执行吗?

那么直接跳转到对应的catch语句中,try下面的代码就不会在执行了

当catch里面的语句全部执行完毕,表示整个体系全部执行完全,继续执行下面的代码

3.如果出现的问题没有被捕获,那么程序如何运行?

那么try…catch就相当于没有写,也就是自己放弃了处理这个异常,交由调用者或者虚拟机处理这个异常

4.同时出现多个异常怎么处理?

出现多个异常,写多个catch就可以了

注意:如果多个异常之间存在子父类关系,父类一定要写在最下面,否则无法精确处理出现的异常

try{
    可能会出现异常的代码段
}catch (异常类名1 变量名){
    处理方案1
}catch (异常类名2 变量名){
    处理方案2
}catch(Exception ex){
    处理方案3   // 注意,Exception是所有异常类的父类,需要写在下面
}

Throwable中的常见方法

  • 常用方法
方法名说明
public String getMessage()返回此throwable的详细消息字符串
public String toString()返回此throwable的简短描述
public void printStackTrace()把异常的错误信息输出在控制台
  • 示例代码
public class ExceptionDemo5 {
    public static void main(String[] args) {

        // 异常处理,把可能出现异常的代码加入到try里面,
        // 当出现异常的时候,用catch捕获并做处理
        try {
            method1();//调用方法的时候,如果输入不符合要求的值,我们就会接收到一个异常对象
            // 我们需要自己处理这个异常
        } catch (ArrayIndexOutOfBoundsException ex) {
            // 返回此throwable的详细消息字符串
            System.out.println(ex.getMessage());
            // 返回throwable的简短描述
            System.out.println(ex.toString());
            // 将错误信息显示在控制台
            ex.printStackTrace();
        }
    }

    private static void method1() {
        int[] arr = {1, 2, 3, 4, 5};
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入索引值:");
        int index = sc.nextInt();
        System.out.println(arr[index]);
    }
}

异常的练习

  • 需求

键盘录入学生的姓名和年龄,其中年龄为18-25岁,超出这个范围使异常数据不能赋值.需要重新录入,一直录到正确为止

  • 实现步骤
    • 创建学生对象
    • 键盘录入姓名和年龄,并赋值给学生对象
    • 如果是非法数据,就再次录入
  • 代码实现
// 学生类
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {

        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age >= 18 && age <= 25) {
            this.age = age;
        } else {
            throw new IndexOutOfBoundsException("年龄超出范围");
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

// 异常类
public class IndexOutOfBoundsException extends RuntimeException {
    public IndexOutOfBoundsException() {
    }
    public IndexOutOfBoundsException(String message) {
        super(message);
    }
}

// StudentController类
import java.util.InputMismatchException;
import java.util.Scanner;

public class StudentController {
    public static void main(String[] args) {
        Student stu = new Student();
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入姓名");
        stu.setName(sc.next());
        System.out.println("请输入年龄(范围18-25):");
        String age;
        while(true){
            age = sc.next();
            try{
                int age1 =Integer.parseInt(age);
                stu.setAge(age1);
                break;
            }catch(NumberFormatException ex){ // 如果输入的是小数,走的是这个
                System.out.println("输入非法,请输入数字");
                continue;
            }
            catch(InputMismatchException ex){ // 如果输入的字符串,走这个
                System.out.println("输入非法,请输入数字");
                continue;
            } 
            //捕捉年龄输入的异常,从年龄学生类的set方法中抛出的异常 
            catch (IndexOutOfBoundsException ex){
                System.out.println("您输入的年龄越界,请重新输入");
                continue;
            }
        }
        System.out.println(stu);
    }
}

小结

1.什么是异常

程序中的不正常称为异常

2.异常的分类

编译器异常和运行时异常

3.谁处理异常

原则上是谁调用谁处理,不想处理throws声明异常,实际开发过程中,尽量不要让jvm处理异常

4.如何捕获异常

通过try…catch来捕获

5.如何手动抛出异常

throw new异常类

6.为什么要自定义异常

在实际开发过程中,有很多异常jdk没有帮我们定义好的,比如age负数或超出范围的异常,因此我们需要根据实际业务自定义异常

7.如何自定义异常

继承RuntimeException,调用父类中的带参构造方法

8.实际开发过程中如何使用异常的原则(看情况)

1.Java类库中定义的可以预检测方式避免,RuntimeException异常不因该通过catch的方式来处理,比如NullPointerException,IndexOutofBoundsException等等

2.catch 时分清稳定代码和非稳定代码,稳定代码指的是无论如何都不会出错的代码,对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理

3.捕获异常是为了处理它,不要捕获了却什么都处理而抛弃,如果不想处理,请将该异常抛弃给它的调用者.最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容

4.捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛出异常的父类

5.避免直接抛出new RuntimeException(),更不允许抛出Exception或者Throwable,应使用有业务含义的自定义异常.推荐业界已定义过的自定义异常,如DAOException/ServiceException等

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值