美文网首页
JavaSE进阶七 异常

JavaSE进阶七 异常

作者: SimonLike | 来源:发表于2021-06-11 16:54 被阅读0次

    1,异常机制

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

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

        Exception in thread "main" java.lang.ArithmeticException:
        这个信息被我们为:异常信息,这个信息是JVM打印的。
      
    • 总结:

      • 什么是异常,程序执行过程中的不正常情况。
      • 异常的作用:增强程序的健壮性。
    代码示例
    public class ExceptionTest01 {
        public static void main(String[] args) {
            // System.out.println(10/0);// 出现异常  Exception in thread "main" java.lang.ArithmeticException:
    
            // 通过"异常类"实例化异常对象
            NumberFormatException numberFormatException = new NumberFormatException("数字格式化异常!");
            System.out.println(numberFormatException);
            NullPointerException nullPointerException = new NullPointerException("空指针异常!");
            System.out.println(nullPointerException);
        }
    
    }
    

    2,异常的存在形式

    • 异常在java中以类的形式存在,每一个异常类都可以创建异常对象。
    • 类是模板,对象是实际存在的个体。
    • Object下有个Throwable(可抛出的),Throwable有两个分支:
      • Error(不可处理,直接退出jvm)
      • Exception(可处理的):
        • Exception的直接子类:编译时异常
          • 要求程序员编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常。
          • 受检异常:CheckedException
          • 受控异常:
        • RunTimeException:运行时异常。
          • 在编写程序阶段程序员可以预先处理,也可以不管,都可以。
          • 未受检异常:UnCheckedException
          • 未受控异常:
    • 编译时异常和运行时异常,都是发生在运行阶段,编译阶段异常是不会发生的。因为只要程序运行阶段才可以new对象,异常的发生就是new异常对象。
    • 编译时异常和运行时异常的区别:
      • 编译时异常一般发生的概率比较高
      • 运行时异常一般发生的概率比较低

    3,异常的处理

    • Java语言中对异常的处理包括两种方式:
      • 1,在方法声明的位置上,使用throws关键字,抛给上一级。
      • 2,使用try..catch语句进行异常的捕捉。
    • 注意:java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续上抛,抛给了调用者JVM,JVM知道了这个
      异常发生,只有一个处理结果:终止java程序的执行。

    3.1 分析异常案例

    public class ExceptionTest02 {
        public static void main(String[] args)  {
            /*
                System.out.println(100/0);
                程序执行发生了ArithmeticException异常,底层new了一个ArithmeticException异常对象,
                然后抛出了,由于是main方法调用了"100/0",所以这异常ArithmeticException抛给了main
                方法,main方法没有处理,将这个异常抛给了JVM,JVM终止了程序的执行。
    
                ArithmeticException继承RunTimeException,属于运行时异常,
                在编写程序阶段不需要对这种异常进行预先处理。
             */
            // System.out.println(100/0);
            // ------------------------------------------------------------------------------
    
            // 调用doSome方法
            // 因为doSome方法声明位置上有throws ClassNotFoundException
            // 所以我们在调用doSome方法时候必须对这种异常进行预先处理,如果不处理编译器会报错
            // 编译报错信息: java: 未报告的异常错误java.lang.ClassNotFoundException; 必须对其进行捕获或声明以便抛出
           
            // doSome();
    
        }
    
        /**
         * doSome方法在方法声明的位置使用了throws ClassNotFoundException
         * 表示doSome方法在执行过程中,有可能会出现ClassNotFoundException异常
         * 叫做类没有找到异常,这个异常值接父类Exception,所以ClassNotFoundException属于编译异常
         * @throws ClassNotFoundException
         */
        public static void doSome() throws ClassNotFoundException{
            System.out.println("ClassNotFoundException");
        }
    }
    

    3.2 处理异常

    public class ExceptionTest03 {
    
        // 第一种处理方式,在声明方法的位置上继续使用throws,异常继续上抛,抛给调用者。
    //    public static void main(String[] args) throws ClassNotFoundException {
    //        doSome();
    //    }
    
        public static void main(String[] args) {
            // 第二种处理方式:try..catch进行捕捉
            try {
                doSome();
            } catch (ClassNotFoundException e) {
                // catch捕捉异常之后,处理异常
                e.printStackTrace();
            }
        }
    
        /**
         * doSome方法在方法声明的位置使用了throws ClassNotFoundException
         * 表示doSome方法在执行过程中,有可能会出现ClassNotFoundException异常
         * 叫做类没有找到异常,这个异常值接父类Exception,所以ClassNotFoundException属于编译异常
         * @throws ClassNotFoundException
         */
        public static void doSome() throws ClassNotFoundException{
            System.out.println("ClassNotFoundException");
        }
    }
    

    3.3 异常对象的两个重要方法:

    • 获取异常简单的描述信息

        String msg = exception.getMessage();
      
    • 打印异常追踪的堆栈信息:

        exception.printStackTrace();
      
    代码示例
    public class ExceptionTest05 {
        public static void main(String[] args) {
            NullPointerException e = new NullPointerException("空指针异常");
            String msg = e.getMessage();
            System.out.println(msg);// 空指针异常
            //  打印异常追踪的堆栈信息
            e.printStackTrace(); // java.lang.NullPointerException: 空指针异常
    
            System.out.println("hello world"); // e.printStackTrace();  不影响hello world的输出
        }
    }
    

    3.4 处理异常深入了解try..catch

    • catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常的父类型。
    • catch可以写多个,建议catch的时候,精确的一个一个的处理。这样有利于程序的调试。
    • catch写多个的时候,从上到下,必须遵守从小到大。
    代码示例
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class ExceptionTest04 {
        public static void main(String[] args) {
    
            try {
                FileInputStream fis = new FileInputStream("");
                fis.read();
                //
                System.out.println(100/0); // 这个异常是运行时异常,编写程序时可以处理,也可以不处理。
            }catch (FileNotFoundException e){ // 所有异常都走catch分支
                System.out.println("文件不存在");
            }catch (ArithmeticException | NullPointerException e){ // jdk8之后新特性 可以用|的形式编写
                System.out.println("读取文件失败");
            }catch (IOException e){
    
            }
        }
    }
    

    3.5 关于try..catch中finally子句

    • 在finally子句中的代码是最好执行的,并且一定会执行,即使try语句块中的代码出现了异常。
      • finally子句必须和try一起出现,不能单独编写。
    • finally语句通常使用在哪些情况下呢?
      • 通常在finally语句块中完成资源的释放/关闭,因为try语句块中的代码出现异常,finally中的代码也会正常执行。
    代码示例
    public class ExceptionTest06 {
        public static void main(String[] args) {
            FileInputStream fis = null;
            try {
                // 创建输入流对象
                fis = new FileInputStream("");
                String s = null;
                s.toString(); // 这里会出现空指针异常
    
                // 流使用完需要关闭,因为流是占用资源的
                // 即使程序出现了异常,流也必须关闭!
                // 放在这里有可能关闭不了。
                fis.close();
            }catch (FileNotFoundException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }catch (NullPointerException e){
                e.printStackTrace();
            }finally {
                // 流的关闭放在这里比较保险,finally中的代码一定会执行的。
                if (fis != null){
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    3.6 finally面试题

    3.6.1 final、finally、finalize有什么区别
    •   final是一个关键字,表示最终的不变的
        finally也是一个关键字,和try联合使用,使用在异常处理机制中,在finally语句块中的代码一定会执行。
        finalize是标识符,是Object类中的一个方法,作为方法名出现。
      
    3.6.2 分析下面程序的运行结果
    public class ExceptionTest08 {
        public static void main(String[] args) {
            int result = m();
            System.out.println(result);// 100
        }
        /*
            java语法规则
                方法体中的代码必须遵循自上而下顺序依次执行,
                return语句一旦执行,整个方法必须结束。
         */
    
        public static int m(){
            int i = 100;
            try {
                // 这行代码出现在int i = 100的下面,所以最终结果必须是返回100
                // return语句还必须保证是最后执行的,一旦执行整个方法结束。
                return i;
            }finally {
                i++;
            }
        }
    }
    

    上篇:JavaSE进阶六 通用类
    下篇:JavaSE进阶八 集合一 Collection接口

    相关文章

      网友评论

          本文标题:JavaSE进阶七 异常

          本文链接:https://www.haomeiwen.com/subject/efgqsltx.html