• Java基础异常


    1、什么是异常,java提供异常处理机制有什么用?

    以下程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常
    java语言是很完善的语言,提供了异常的处理方式,以下程序执行过程中出现了不正常情况,
    java把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对
    程序进行修改,让程序更加的健壮。

    什么是异常:程序执行过程中的不正常情况。
    异常的作用:增强程序的健壮性。

    以下程序执行控制台出现了:

    Exception in thread "main" java.lang.ArithmeticException: / by zero
           at com.bjpowernode.javase.exception.ExceptionTest01.main(ExceptionTest01.java:14)
    
    • 1
    • 2

    这个信息被我们称为:异常信息。这个信息是JVM打印的。

    示例代码01:

    public class ExceptionTest01 {
        public static void main(String[] args) {
            /*int a = 10;
            / 实际上JVM在执行到此处的时候,会new异常对象:new ArithmeticException("/ by zero");
            // 并且JVM将new的异常对象抛出,打印输出信息到控制台了。
            int b = 0;
            int c = a / b;
            System.out.println(a + "/" + b + "=" + c);*/
            // 此处运行也会创建一个:ArithmeticException类型的异常对象。
            //System.out.println(100 / 0);
    
            // 我观察到异常信息之后,对程序进行修改,更加健壮。
    
            int a = 10;
            int b = 0;
    
            if(b == 0){
                System.out.println("数字错误,b不能为0!");
                return;
            }
            // 程序执行到此处表示除数一定不是0
    
            int c = a / b;
            System.out.println(a + "/" + b + "=" + c);
        }
    }
    运行结果:
    数字错误,b不能为0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2、java语言中异常是以什么形式存在的呢?

    • 异常在java中以类的形式存在,每一个异常类都可以创建异常对象。
    • 异常对应的现实生活中是怎样的?
    • 火灾(异常类):
      • 2008年8月8日,小明家着火了(异常对象)
      • 2008年8月9日,小刚家着火了(异常对象)
      • 2008年9月8日,小红家着火了(异常对象)
    • 类是:模板。
    • 对象是:实际存在的个体
    • 钱包丢了(异常类):
      • 2008年1月8日,小明的钱包丢了(异常对象)
      • 2008年1月9日,小芳的钱包丢了(异常对象)

    示例代码02:

    public class ExceptionTest02 {
        public static void main(String[] args) {
            NumberFormatException num = new NumberFormatException("数字格式化异常!");
            //java.lang.NumberFormatException: 数字格式化异常!
            System.out.println(num);
    
            NullPointerException nul = new NullPointerException("空指针异常!");
            //java.lang.NullPointerException: 空指针异常!
            System.out.println(nul);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3、异常处理机制

    • java中异常的作用是:增强程序健壮性。

    • java中异常以类和对象的形式存在。

    • Object下有Throwable(可抛出的)

    • Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)

      Exception下有两个分支:

    • Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错)

    • RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不管,都行)

    编译时异常和运行时异常,都是发生在运行阶段。编译阶段异常是不会发生的。

    4、编译时异常因为什么而得名?

    • 因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。
      所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象。
      因为异常的发生就是new异常对象。

    5、编译时异常和运行时异常的区别?

    • 编译时异常一般发生的概率比较高。

    举个例子:
    你看到外面下雨了,倾盆大雨的。
    你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。
    而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。
    “拿一把伞”就是对“生病异常”发生之前的一种处理方式。

    对于一些发生概率较高的异常,需要在运行之前对其进行预处理。

    • 运行时异常一般发生的概率比较低。

    举个例子:
    小明走在大街上,可能会被天上的飞机轮子砸到。
    被飞机轮子砸到也算一种异常。
    但是这种异常发生概率较低。
    在出门之前你没必要提前对这种发生概率较低的异常进行预处理。
    如果你预处理这种异常,你将活的很累。

    假设你在出门之前,你把能够发生的异常都预先处理,你这个人会更加
    的安全,但是你这个人活的很累。

    6、编译时异常还有其它名字:

    • 受检异常:CheckedException

    • 受控异常

      运行时异常还有其它名字:

    • 未受检异常:UnCheckException

    • 非受检异常

    再次强调:所有异常都是发生在运行阶段的

    7、Java语言中对异常的处理包括两种方式:

    • 第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。
      谁调用我,我就抛给谁。抛给上一级。上报
    • 第二种方式:使用try…catch语句进行异常的捕捉。
      这件事发生了,谁也不知道,因为我给抓住了。不会上报,不会上抛

    举个例子:
    我是某集团的一个销售员,因为我的失误,导致公司损失了1000元,
    “损失1000元”这可以看做是一个异常发生了。我有两种处理方式,
    第一种方式:我把这件事告诉我的领导【异常上抛】
    第二种方式:我自己掏腰包把这个钱补上。【异常的捕捉】

    张三 --> 李四 —> 王五 --> CEO

    思考:
    异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要
    对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。

    注意:Java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续
    向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止java程序的执行。

    示例代码03:

    public class ExceptionTest03 {
        public static void main(String[] args) {
    
            /*
            * 程序执行到此处发生了ArithmeticException异常,
            * 底层new了一个ArithmeticException异常对象,
            * ,然后跑出了,由于是main方法调用了100/0,
            * 所以这个异常ArithmeticException抛给了main方法,
            * main方法没有处理,将这个异常自动抛给了JVM
            * JVM最终终止程序的执行
            *
            * ArithmeticException 继承RuntimeException,属于运行时异常
            * 在编写程序阶段不需要对这种异常进行预先的处理
            * */
            int i = 10;
            int a = 0;
            System.out.println(i / a);
    
            //这里的HelloWorld没有输出,没有执行
            System.out.println("HelloWorld!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    示例代码04:

    /*
    * 以下代码报错的原因是什么?
    *    因为doSome()方法声明位置上使用了:throws ClassNotFoundException
    *    而ClassNotFoundException是编译时异常。必须编写代码时处理,没有处理编译器报错。
    * */
    public class ExceptionTest04 {
        public static void main(String[] args) {
            //main方法中调用doSome()方法
            //因为dosome()方法声明位置上有:throws ClassNOtFoundException
            //我们在调用doSome()方法时必须对这种对象进行预先的处理
            //如果不处理,编译器就报错
            //编译器报错信息: UnHandled exception:java.lang.ClassNotFoundException
            //doSome();
        }
    
        /**
         * doSome方法在方法声明的位置上使用了:throws ClassNotFoundException
         * 这个代码在表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常
         * 叫做类没找到异常,这个异常直接父类是:Exception,所以ClassNotFoundException属于编译时异常
         * @throws ClassNotFoundException
         */
        public static void doSome() throws ClassNotFoundException{
            System.out.println("异常测试方法!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    示例代码05:

    public class ExceptionTest05 {
    
        //第一种处理方式,把异常抛给上一级
        //在方法声明位置上继续使用:throws,来完成异常的继续上抛。抛给调用者。
        //上抛类似于推卸责任。(继续把异常传递给调用者)
        public static void main(String[] args) throws Exception{
    
           //第二种处理方式
            //捕捉等于把异常来下了,异常真正的解决了。(调用者是不知道的)
           try{
               doSome();
           }catch(ClassNotFoundException e){
               e.printStackTrace();
           }
        }
    
        public static void doSome() throws ClassNotFoundException{
            System.out.println("输出类找不到异常!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    注意:
    只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行。
    另外需要注意,try语句块中的某一行出现异常,该行后面的代码不会执行。
    try…catch捕捉异常之后,后续代码可以执行。

    在以后的开发中,处理编译时异常,应该上报还是捕捉呢,怎么选?
    如果希望调用者来处理,选择throws上报。
    其它情况使用捕捉的方式。

    示例代码06:

    public class ExceptionTest06 {
        public static void main(String[] args) {
            //一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。
            //异常处理机制的作用就是增强程序的健壮性。怎么能做到,异常发生了也不影响程序的执行。所以
            //一般main方法中的异常建议使用try..catch进行捕捉。main就不要继续上抛了。
            // 100 / 0这是算术异常,这个异常是运行时异常,你在编译阶段,可以处理,也可以不处理。编译器不管。
            //System.out.println(100 / 0); // 不处理编译器也不管
            // 你处理也可以。
            /*
            try {
                System.out.println(100 / 0);
            } catch(ArithmeticException e){
                System.out.println("算术异常了!!!!");
            }
             */
            //try.caytch把异常捕捉之后,这里的代码会继续执行
            System.out.println("main begin!");
            try {
                //try尝试
                m1();
                //以上代码出现异常,直接进入catch语句块中执行
            }catch(FileNotFoundException e){//catch后面的好像一个方法的形参
                //这个分支中可以使用e引用,e引用保存的内存地址是
                //catch是捕捉异常之后走的分支
                //在catch分支中干什么?处理异常
                System.out.println("文件异常,文件路径错误,或者文件不存在!");
            }
            //try..catch把异常抓住之后,这里的代码会继续执行
            System.out.println("main over!");
        }
    
        public static void m1() throws FileNotFoundException{
            System.out.println("m1 begin!");
            m2();
            //以上出现异常,这里是无法执行的!
            System.out.println("m1 over!");
        }
    
        //抛别的不行,抛ClassCastException说明你还是没有对FileNotFoundException进行处理
        //private static void m2() throws ClassCastException{
        //抛FileNotFoundException的父对象IOException,这样是对的。因为IOException包括FileNotFoundException
        //private static void m2() throws IOExcception
        //这样也可以,因为Exception包括所有的异常
        //private static void m2() throws Exception
        //throws后面也可以写多个异常,可以使用逗号隔开
        //private static void m2() throws ClassCastException,FileNotFoundException
        public static void m2() throws ClassCastException,FileNotFoundException{
            System.out.println("m2 begin!");
            //编译器报错的原因是:m3()方法声明位置上有:throws FileNotFoundException
            //我们在这里调用m3()没有对异常进行预处理,所以编译报错
            //m3();
            m3();
            //以上出现异常,这里是无法执行的!
            System.out.println("m2 over!");
        }
    
        public static void m3() throws FileNotFoundException {
            //调用SUN jdk中每个类的构造方法
            //这个类还没有接触过,后期IO流的时候就知道了
            //这里借助这个类学习以下异常处理机制
            //创建一个输出流对象,该流指向一个文件
            /*
            * 编译报错的原因是什么?
            * 第一:这里调用了一个构造方法:FileNotFoundException(String name)
            * 第二:这个构造方法的声明的位置上有:throws FileNotFoundException
            * 第三:通过类的继承结构看到:FileNotFoundException父类是IOException,IOException的父类是Exception
            * 最终得知:FileNotFoundException是编译时异常
            *
            * 错误原因?编译时异常要求程序员编写阶段必须对它进行处理,不处理编译器就报错
            * */
            //我们采用第一种处理方式:在方法声明的位置上使用throws继续上抛
            //一个方法体当中的代码出现异常之后,如果上报的话,此方法结束。
            new FileInputStream("D:\\Notepad++\\config.java");//\是转义
    
            System.out.println("如果以上代码出现异常,这里会执行吗?????????不会!!!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    运行结果:

    在这里插入图片描述

    示例代码08:

    public class ExceptionTest07 {
    
        public static void main(String[] args) {
    
            try {
                FileInputStream fis = new FileInputStream("D:\\Notepad++\\config.xml");
                System.out.println("以上出现异常,这里无法执行!");
            }catch(FileNotFoundException e){
                System.out.println("文件不存在!");
            }
    
            try{
                FileInputStream fis = new FileInputStream("D:\\Notepad++\\config.xml");
            }catch(IOException e){//多态 IOException e = new FileNotFoundException();
                System.out.println("文件不存在!");
            }
    
            try{
                FileInputStream fis = new FileInputStream("D:\\Notepad++\\config.xml");
            }catch(Exception e){//多态 Exception e = new FileNotFoundException();
                System.out.println("文件不存在!");
            }
    
            try{
                FileInputStream fis = new FileInputStream("D:\\Notepad++\\config.xml");
                fis.read();
            }catch(FileNotFoundException e){
                System.out.println("文件不存在!");
            }catch(IOException e){
                System.out.println("读文件报错了!");
            }
    
            try{
                FileInputStream fis = new FileInputStream("D:\\Notepad++\\config.xml");
                fis.read();
            }catch(Exception e){//多态 IOException e = new FileNotFoundException();
                System.out.println("文件不存在!");
            }
    
            /*try{
                FileInputStream fis = new FileInputStream("D:\\Notepad++\\config.xml");
                fis.read();
            }catch(IOException e){
                System.out.println("文件异常!");
            }catch(FileNotFoundException e){//报错,因为IOException已经包括FileNotFoundException
                System.out.println("文件不存在!");
            }*/
            // JDK8的新特性!
            try{
                FileInputStream fis = new FileInputStream("D:\\Notepad++\\config.xml");
                fis.read();
                System.out.println( 10 / 0);
            }catch(IOException | ArithmeticException | NullPointerException e){
                System.out.println("文件不存在 | 读文件报错 | 数字异常 | 空指针异常");
            }
    
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    运行结果:

    在这里插入图片描述

  • 相关阅读:
    [英雄星球七月集训LeetCode解题日报] 第20日 BST
    【leetcode】【2022/8/12】1282. 用户分组
    git工作流
    KubeCon热点报告:AIStation调度平台实现RoCE网络下大模型的高效稳定训练
    pandas 使用 isin 判断 字符是否在列表中的方法提示错误的解决方法
    数字化转型迈向深水区:银行业不断夯实科技根基
    C语言volatile关键字、内嵌汇编volatile与编译器的爱恨情仇
    IB-MYP课程知道为什么这么难吗?从课程讲起
    LLVM之父Chris Lattner:模块化设计决定AI前途,不服来辩
    ThreeJS-3D教学五-材质
  • 原文地址:https://blog.csdn.net/qq_46096136/article/details/126660104