深入理解java的异常情况

编辑: admin 分类: java 发布时间: 2021-12-03 来源:互联网
目录
  • 什么是异常?
  • 异常的存在形式
  • Java异常体系
  • 异常的分类
    • 运行时异常
    • 编译时异常
    • 错误 Error
    • 编译时异常和运行时异常的区别
    • 常见的异常
  • 防御式编程
    • Java处理异常的语法
      • 异常抛出—throws
        • 异常捕获—try…catch
    • 自定义异常类
      • 总结

        什么是异常?

        在程序的运行或者编译时,所产生的错误统称为异常 (也叫Bug)

        异常的存在形式

        异常在java中以类的形式存在,每一个异常类都可以创建异常对象

        我们平时看到的异常,都被封装成一个类

        例如:0 为除数,异常为:ArithmeticException

        查看在线文档会发现:

        在这里插入图片描述

        Java异常体系

        在这里插入图片描述

        异常的分类

        异常分为:运行时异常 和 编译时异常

        运行时异常

        运行时异常又称为:非受查异常,指的是在程序运行时所抛出的异常

        特点:Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过

        编译时异常

        编译时异常又称为:受查异常,在程序编译时的异常

        是RuntimeException以外的异常,类型上都属于Exception类及其子类,从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过

        错误 Error

        是程序无法处理的错误,表示运行应用程序中较严重问题

        错误是预测不到的,如果应用程序出现了Error,那么将无法恢复,只能重新启动应用程序

        编译时异常和运行时异常的区别

        编译时异常 运行时异常 发生概率 比较高 比较低 处理方式 需要在运行之前对其进行 预处理 没必要提前进行预处理

        常见的异常

        我们之前已经接触了一些异常,常见的异常还是有必要记住的

        0为除数(算数异常)

        int a = 10 / 0;
        

        在这里插入图片描述

        数组下标越界(数组下标越界异常)

        int[] array = {1,2,3};
        System.out.println(array[4]);
        

        在这里插入图片描述

        访问 null(空指针异常)

        空指针异常出现的概率非常高!!

        int[] array = {1,2,3};
        array = null;
        System.out.println(array[2]);
        

        在这里插入图片描述

        防御式编程

        程序出现问题的时候及时通知程序猿,主要有两种主要的方式:

        BYBL

        Look Before You Leap,在操作之前就做充分的检查

        举例:一个男孩子很喜欢一个女孩子,想要拉女孩子的手,提前问:我可以拉你的手嘛?

        EAFP

        It's Easier to Ask Forgiveness than Permission,“事后获取原谅比事前获取许可更容易”,也就是先操作,遇到问题再处理

        举例:男孩子先拉的女孩子的手,女孩子很生气,呼了一巴掌,男孩子再回来巴拉巴拉道歉

        异常的核心就是EAFP

        Java处理异常的语法

        异常抛出—throws

        指编程人员主动抛出一个异常

        任何Java代码都可以抛出异常,在方法声明的位置上使用 throws 关键字抛出,抛给方法的调用者来处理,这种处理异常的态度:上报

        举例:

        public static void testThrows() throws NullPointerException {
            Integer p = null;
            System.out.println(p + 1);
        }
        

        注意:

        • 方法的调用者负责处理该异常
        • 在定义方法时,把异常抛出就是为了提醒方法的使用者,有异常需要预处理
        • 如果异常对象是 非RuntimeException,则需要在方法申明时加上该异常的抛出
        • 即需要加上 throws 语句 或者 在方法体内 try catch 处理该异常,否则编译报错
        • 执行到 throw 语句,后面的语句块不再执行

        异常捕获—try…catch

        这个异常不会上报,自行处理,异常抛到此处为止,不再上抛

        try {
         //可能出现异常的代码
        } 
        catch (Exception1 e) { //参数:异常的类型 e
        //捕获try当中可能出现的异常
        } 
        catch (Exception2 e) { //参数:异常的类型 e
        //捕获try当中可能出现的异常
        } finally {
        
        }
        

        举例:

        int[] array = {2,4,6,8};
        try{
            System.out.println(array[4]);
        }
        catch (ArrayIndexOutOfBoundsException e){
            System.out.println("捕获到数组越界异常!");
        }
        

        对比:

        在这里插入图片描述

        注意:

        • try{ } 包含了可能出现异常的代码
        • catch 可以有一个或多个,catch中是捕获 try 当中可能出现的异常,可以通过 catch 捕获多个异常
        • catch 块当中,一定要捕获相应的异常,如果程序抛出的异常在 catch 块当中不能被捕获,则会交给JVM来处理异常,程序便会异常终止
        • 当 try 中的代码出现异常时,try 里异常之后的代码不会执行,马上会跳转到相应的catch语句块中,如果没有异常便不会跳转
        • 不管是否出现异常,finally{ } 里的代码都执行,finally和catch可以分开使用,但finally必须和try一块使用
        • 不建议直接捕获 Exception 异常,要捕获就捕获具体的
        • 不建议在 finally 中出现 return语句
        • catch 只能处理对应种类的异常

         try 负责回收资源

        Scanner scan = new Scanner(System.in);
        try{
            int n = scan.nextInt();
            System.out.println(10/n);
        }
        catch (ArithmeticException e){
            e.printStackTrace();
        }
        finally {
            scan.close();
        }
        

        在Idea里,会发现 try 背景色会加深,将鼠标放在 try,按 Alt + Enter

        在这里插入图片描述

        在这里插入图片描述

        出现上图,回车即可!

        然后代码就会自动被优化:

        在这里插入图片描述

        即:将 Scan 对象在 try( )中创建,就能保证在 try 执行完毕后自动调用 Scanner 的 close 方法

        向上传递,处理异常

        先看代码:

        public static void func(){
            int[] array = {2,4,6,8};
            System.out.println(array[4]);
        }
        public static void main(String[] args) {
            func();
        }
        

        上述代码,func 方法里存在数组越界异常,但并没有处理,到 main 中调用 func 方法,由于 main方法里也没有处理该异常,则会交给 JVM,那么程序一运行,遇到异常,直接就会终止

        改进:

        public static void func(){
            int[] array = {2,4,6,8};
            System.out.println(array[4]);
        }
        public static void main(String[] args) {
            try {
                func();
            }
            catch (ArrayIndexOutOfBoundsException e){
                e.printStackTrace();
            }
            finally {
                System.out.println("hahaha");
            }
        

        异常的传递是可以沿着栈向上传递的,方法是要在栈上开辟内存的

        处理流程

        • 程序先执行 try 中的代码
        • 若 try 中的代码出现异常,就会结束 try 中的代码,看和 catch 中的异常类型是否匹配
        • 若找到匹配的异常类型,就会执行 catch 中的代码
        • 若没有找到匹配的异常类型,就会将异常向上传递到上层调用者
        • 无论是否找到匹配的异常类型,finally 中的代码都会被执行到(在该方法结束之前执行)
        • 若上层调用者也没有处理的了异常,就继续向上传递
        • 一直到 main 方法也没有合适的代码处理异常,就会交给 JVM 来进行处理,此时程序就会异常终止

        自定义异常类

        自定义异常类步骤:

        编写一个类继承 Exception 或者 RuntimeException提供两个 构造方法,一个无参数的,一个带有 String 参数的

        class MyException extends RuntimeException{
            //构造方法
            public MyException() {
                super();
            }
            public MyException(String message) {
                super(message);
            }
        }
        

        自己玩~~

        public static void func(int x){
            if(x == 10){
                throw new MyException("x==10");
            }
        }
        public static void main(String[] args) {
            try {
                func(10);
            }
            catch (MyException e){
                e.printStackTrace();
            }
        }
        

        输出结果:

        在这里插入图片描述

        注意事项:

        • 一定要继承一个父类异常,通常是 Exception / RuntimeException
        • 一般建议继承Exception,好处是必须要处理异常

        总结

        本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注自由互联的更多内容!

        【文章来自:高防ip处的文章,转载请说明出处】