zoukankan      html  css  js  c++  java
  • java基础(三):谈谈java异常的处理

    1.知识点总结

    1.1.异常分类

      异常就是java中出现的不正常的现象(错误与异常),按照继承的体系结构,可以分类如下

      Throwable: 它是所有错误与异常的超类(祖宗类)

        |- Error 错误,修改java源代码

        |- Exception 编译期异常, javac.exe进行编译的时候报错

          |- RuntimeException 运行期异常, java出现运行过程中出现的问题

    1.2.异常处理方式

       1.出现问题,自己解决

        try{

          可能出现异常的代码

        } catch(异常类名  对象名){

             异常处理代码

        } finally {

          异常操作中一定要执行的代码

        }

       2.出现问题,别人解决

        格式:

        修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2,...{}

        public void method() throws ATMException{}

    2.异常和错误的区别

    异常:程序在运行期间发生了异常,通常可以有针对性的处理方式的。

    错误:程序在运行期间发生了错误,通常不会有针对性的处理方式。错误的的发生往往都是系统级别的问题,都是jvm所在系统发生的并反馈给jvm的。无法针对处理,只能修正代码。

    异常代码体现:

    class ExceptionDemo {
        public static void main(String[] args) {
            int[] arr = new int[3];
            System.out.println(arr[0]);
            System.out.println(arr[3]);// 该句运行时发生了ArrayIndexOutOfBoundsException,导致程序无法继续执行。程序结束。
            System.out.println("over"); // 由于上面代码发生了异常,此句代码不会执行
        }
    }

     错误的体现:

    int[] arr = new int[1024*1024*100];//OutOfMemoryError 开辟了过大的数组空间,导致JVM在分配数组空间时超出了JVM内存空间,直接发生错误。

    3.异常的发生过程

    class ArrayTools{
        /*
        对给定的数组通过给定的角标获取元素。
        */
        int getElement(int[] arr,int index)    {
            /*
            没有找到4个角标。运行时发生了问题,这个问题JVM认识。这个问题java本身有
            描述:描述内容有:问题的名称,问题的内容,问题的发生位置。既然有这么多的信
            息。java就将这些信息直接封装到对象中。ArrayIndexOutOfBoundsException
            */
            int element = arr[index];//throw new ArrayIndexOutOfBoundsException(index);
            return element;
        }
    }
    class ExceptionDemo2 {
        public static void main(String[] args)     {
            ArrayToolsd = new ArrayTools();
            int[] arr = {34,12,67};
            int num = d.getElement(arr,4);//收到 new ArrayIndexOutOfBoundsException(index);抛出jvm。jvm进行最终处理。将问题的名称,信息,位置都显示屏幕上。
            System.out.println("num="+num);
            System.out.println("over");
        }
    }

    4.异常的应用

    在编写程序时,必须要考虑程序的问题情况。比如在写功能时,需要接受参数,在使用功能中使用接受到的参数时,首先需要先对参数数据进行合法的判断,数据若不合法,应该告诉调用者,传递合法的数据进来。这时需要使用异常这种方法来告诉调用者。所以定义程序需要考虑程序的健壮性

    class ArrayTools{
        /*
        对给定的数组通过给定的角标获取元素。
        */
        int getElement(int[] arr,int index)    {
            /*
            jvm出了问题,自己打包对象并抛出。但是它所提供的信息不够给力。想要更清晰,
            需要自己写。它的抛出不满足我们的要求。准备自己抛。
            */
            if(arr==null)    {
                throw new NullPointerException("arr指向的数组不存在");
            }
            if(index<0 || index>=arr.length){
                //该条件如果满足,功能已经无法继续运算。这时就必须结束功能,并将问题告知给调用者。这时就需要通过异常来解决。
                //怎么使用异常呢?
                //1,创建一个异常对象。封装一些提示信息(自定义)。
                //2,需要将这个对象告知给调用者。怎么告知呢?怎么将这个对象传递到调用者处呢?通过关键字throw就可以完成。 throw 异常对象;
                //3,throw用在函数内,抛出异常对象,并可以结束函数。
                throw new ArrayIndexOutOfBoundsException("错误的角标,"+index+"索引在数组中不存在");
            }
            int element = arr[index];
            return element;
        }
    }
    class ExceptionDemo3 {
        public static void main(String[] args) {
            Demo d = new Demo();
            int[] arr = {34,12,67};
            int num = d.getElement(null,2);
            System.out.println("num="+num);
            System.out.println("over");
        }
    }

    5.异常的分类

    在查阅API时,发现异常有分类,并且有些编辑报错,有些编译不报错,那到底是为什么呢?

    在上述自定义异常中继承Exception和继承RuntimeExcpetion为什么差距这么大?

      1、Exception异常(非RuntimeException)

      在函数内抛出Exception,编译失败,因为编译器在检查语法时发生了错误。该程序已经出现问题,Java认为这个程序本身存在隐患,需要捕获或者声明出来(你要么把问题处理,要么把问题标识出来让调用知道)

       2、RuntimeException异常

      为什么抛出RuntimeException,不需要捕获,不要声明呢?不是功能本身发生的异常,而是因为比如调用者传递参数错误而导致功能运行失败。这也是问题,需要通过异常来体现,但是这个异常不要声明出来的。声明的目的是为了让调用者进行处理。不声明的目的是不让调用者进行处理,就是为了让程序停止,让调用者看到现象,并进行代码的修正。

      3、异常分两种:

      a、编译时异常:编译器会检测的异常。

      b、运行时异常:编译器不会检测的异常。不需要声明。声明也可以,如果声明了,无外 乎就是让调用者给出处理方式。

    6.声明和捕获

    在研究异常分类时,发现有关于异常的声明和捕获,到底啥是异常声明,啥是异常捕获呢?

      声明:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获,那么必须通过throws进行声明,让调用者去处理。

      捕获:Java中对异常有针对性的语句进行捕获。

    捕获格式:

    try
    {
        //需要被检测的语句。
    }
    catch(异常类 变量)//参数。
    {
        //异常的处理语句。
    }
    finally
    {
        //一定会被执行的语句。
    }
    class Demo{
        /*
        如果定义功能时有问题发生需要报告给调用者。可以通过在函数上使用throws关键字进行声明。
        */
        void show(int x)throws Exception    {
            if(x>0){
                throw new Exception();
            } else {
                System.out.println("show run");
             }
        }
    }
    class ExceptionDemo{
        public static void main(String[] args) {//throws Exception//在调用者上继续声明。 
            Demo d = new Demo();
            try    {
                d.show(1);//当调用了声明异常的方法时,必须有处理方式。要么捕获,要么声明。
            }
            catch (Exception ex) { //括号中需要定义什么呢?对方抛出的是什么问题,在括号中就定义什么问题的引用。
                System.out.println("异常发生了");
            }
            System.out.println("Hello World!");
        }
    }

    声明和捕获的应用

    1 class NoAgeException extends RuntimeException{
    2     NoAgeException() {
    3         super();
    4     }
    5 
    6     NoAgeException(String message)    {
    7         super(message);
    8     }
    9 }
     1 class Person{
     2     private String name;
     3     private int age;
     4     Person(String name,int age)//throws NoAgeException    {
     5         //加入逻辑判断。
     6         if(age<0 || age>200)        {
     7             throw new NoAgeException(age+",年龄数值非法");
     8         }
     9         this.name = name;
    10         this.age = age;
    11     }
    12     //定义Person对象对应的字符串表现形式。覆盖Object中的toString方法。
    13     public String toString()    {
    14         return "Person[name="+name+",age="+age+"]";
    15     }
    16 }
     1 class ExceptionDemo{
     2     public static void main(String[] args) {
     3         try {
     4             Person p = new Person("xiaoming",20);
     5             System.out.println(p);
     6         }
     7         catch (NoAgeException ex){
     8             System.out.println("异常啦");
     9         }
    10         System.out.println("over");
    11     }
    12 }

    构造函数到底抛出这个NoAgeException是继承Exception呢?还是继承RuntimeException呢?

    继承Exception,必须要throws声明,一声明就告知调用者进行捕获,一旦问题处理了调用者的程序会继续执行。

    继承RuntimeExcpetion,不需要throws声明的,这时调用是不可能编写捕获代码的,因为调用根本就不知道有问题。一旦发生NoAgeException,调用者程序会停掉,并有jvm将信息显示到屏幕,让调用者看到问题,修正代码。

    7.自定义异常

    在上述代码中,发现这些异常都是JDK内部定义好的,并且这些异常不好找。书写时也很不方便,那么能不能自己定义异常呢?

    之前的几个异常都是java通过类进行的描述。并将问题封装成对象,异常就是将问题封装成了对象。这些异常不好认,书写也很不方便,能不能定义一个符合我的程序要求的问题名称。既然JDK中是使用类在描述异常信息,那么我们也可以模拟Java的这种机制,我们自己定义异常的信息,异常的名字,让异常更符合自己程序的阅读。准确对自己所需要的问题进行类的描述。

     1  class NoAgeException 
     2  {
     3      /*
     4      为什么要定义构造函数,看到Java中的异常描述类中有提供对问题对象的初始化方法。
     5 */
     6      NoAgeException()
     7      {
     8      }
     9      NoAgeException(String message)
    10      {
    11      }
    12  }
    13 
    14  class Person{
    15      private String name;
    16      private int age;
    17      Person(String name,int age)    {
    18          //加入逻辑判断。
    19          if(age<0 || age>200){
    20              throw new NoAgeException(age+",年龄数值非法");
    21          }
    22          this.name = name;
    23          this.age = age;
    24      }
    25      //定义Person对象对应的字符串表现形式。覆盖Object中的toString方法。
    26      public String toString(){
    27          return "Person[name="+name+",age="+age+"]";
    28      }
    29  }
    30 
    31  class ExceptionDemo{
    32      public static void main(String[] args)     {
    33          Person p = new Person("xiaoming",-20);
    34          System.out.println(p);
    35      }
    36  }

    上述代码发生编译失败。

    1 ExceptionDemo.java:19: 错误: 不兼容的类型
    2      throw new NoAgeException(age+",年龄数值非法");
    3                               ^
    4   需要: Throwable
    5   找到:    NoAgeException
    6 1 个错误

    提示中说需要Throwable,啥东西?搜索API。看到Throwable描述。发现。它是异常和错误的超类(父类),原来它是异常体系的顶层类。

    通过阅读:自定义异常被抛出,必须是继承Throwable,或者继承Throwable的子类。该对象才可以被throw抛出。原来这个异常体系具备一个特有的特性:可抛性:可以被throw关键字操作。

    异常继承选择父类时,更为确切是继承Exception。但是发现编译又一次失败了。

     1 class NoAgeException extends  Exception{
     2     /*
     3     为什么要定义构造函数,因为看到Java中的异常描述类中有提供对问题对象的初始化方法。
     4     */
     5     NoAgeException()    {
     6     }
     7 
     8     NoAgeException(String message)    {
     9     }
    10 }
    11 
    12 ExceptionDemo.java:19: 错误: 未报告的异常错误NoAgeException; 必须对其进行捕获或声明以便抛出
    13                         throw new NoAgeException(age+",年龄数值非法");
    14                         ^
    15 1 个错误

    通过这个编译失败提示,发现自定义的异常和之前所使用的异常(空指针异常,角标越界异常,无效参数异常有不同),抛出哪些异常没有这个失败提示?那么之前的异常和自定义的异常有什么区别呢?

    通过查看api的继承体系发现,之前的异常都是Exception下面的RuntimeException子类的子类。阅读RuntimeException描述中有明确说明,这个运行时异常以及其子类都无需进行声明。

    可以将自定义的异常继承RuntimeException.

     1 class NoAgeException extends RuntimeException
     2 {
     3     /*
     4     为什么要定义构造函数,因为看到Java中的异常描述类中有提供对问题对象的初始化方法。
     5     */
     6     NoAgeException()    {
     7     }
     8 
     9     NoAgeException(String message)    {
    10     }
    11 }

    发现编译运行的确正常运行,但是异常提示信息没有了,为什么呢,查阅异常源码,发现自己父类构造函数中有关于异常信息的操作,那么在自己定义的异常中需要将这些信息传递给父类,让父类帮我们进行封装即可。

     1 class NoAgeException extends RuntimeException{
     2     /*
     3     为什么要定义构造函数,因为看到Java中的异常描述类中有提供对问题对象的初始化方法。
     4     */
     5     NoAgeException()    {
     6         super();
     7     }
     8     NoAgeException(String message)    {
     9         super(message);// 如果自定义异常需要异常信息,可以通过调用父类的带有字符串参数的构造函数即可。
    10     }
    11 }

    8.throw、throws和finally

    8.1.throw和throws的区别

      1、throw用在函数内。throws用在函数上。

      2、thorw抛出的是异常对象。throws用于进行异常类的声明,后面异常类可以有多个,用逗号隔开。

    8.2.finally的使用

      有一些特定的代码无论异常是否发生,都需要执行。因为异常会引发程序跳转,导致有些语句执行不到。无法满足这个需求。异常捕获处理时java提供解决方案,finally就是解决这个问题的,这个代码块中存放的代码都是一定会被执行的。

     1 //自定义异常
     2 class NoShowException extends Exception
     3 {
     4     NoShowException(String message)
     5     {
     6         super(message);
     7     }
     8 }
     9 //模拟功能类
    10 class Demo
    11 {
    12     void show(int num) throws NoShowException
    13     {
    14         if(num < 5)
    15         {
    16             throw new NoShowException(num+"非法的数据");
    17         }
    18         System.out.println("show num"+num);
    19     }
    20 }
    21 //测试类
    22 class ExceptionDemo 
    23 {
    24     public static void main(String[] args) 
    25     {
    26         Demo d = new Demo();
    27         try
    28         {
    29             d.show(4);
    30         }
    31         catch (NoShowException ex)
    32         {
    33             System.out.println(ex); //打印异常信息
    34             //如果异常发生,处理完毕后,希望功能结束;
    35             //可以使用return ;
    36         }
    37         finally
    38         {
    39             System.out.println("一直能执行到的代码");
    40         }
    41         System.out.println("Hello World!");
    42     }
    43 }

    总结:finally到底什么时候用?

    只要程序中使用到了具体的资源(数据库连接,IO资源,网络连接socket)需要释放,都必须定义在finally中。你在定义程序,只要问题发生与否,指定程序都需要执行时,就定义finally中。

    8.3.异常细节

    8.3.1.try catch finally组合

      try catch组合 : 对代码进行异常检测,并对检测的异常传递给catch处理。异常捕获处理。

    1 void show(){ //不用throws 
    2     try{
    3         throw new Exception();
    4     }catch(Exception e){
    5 //处理方式    
    6     }
    7 }

       try finally 组合: 对代码进行异常检测,检测到异常后因为没有catch,所以一样会被默认jvm抛出。异常是没有捕获处理的。但是功能所开启资源需要进行关闭,所有finally。只为关闭资源。

    1 void show(){//需要throws 
    2     try{
    3         throw new Exception();
    4     }finally {
    5         //关闭资源
    6     }
    7 }

      try catch finally组合:检测异常,并传递给catch处理,并定义资源释放。

    8.3.2.异常在方法复写中细节

    异常在继承或者实现中的使用细节:

    1、子类覆盖父类方法时,如果父类的方法声明异常,子类只能声明父类异常或者该异常的子类,或者不声明。

    2、当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集。

    3、当被覆盖的方法没有异常声明时,子类覆盖时无法声明异常的。

    举例:父类中会存在下列这种情况,接口也有这种情况,

    问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办?

    答:无法进行throws声明,只能catch的捕获。万一问题处理不了呢?catch中继续throw抛出,但是只能将异常转换成RuntimeException子类抛出。

    参考:

    java编程思想

    黑马视频

     

     

  • 相关阅读:
    bzoj 1030 [JSOI2007]文本生成器
    Swift 学习笔记 (闭包)
    Swift 学习笔记 (函数)
    HTML 学习笔记 JQueryUI(Interactions,Widgets)
    HTML 学习笔记 JQuery(表单,表格 操作)
    HTML 学习笔记 JQuery(animation)
    HTML 学习笔记 JQuery(盒子操作)
    HTML 学习笔记 JQuery(事件)
    HTML 学习笔记 JQuery(DOM 操作3)
    HTML 学习笔记 JQuery(DOM 操作2)
  • 原文地址:https://www.cnblogs.com/dz-boss/p/10260306.html
Copyright © 2011-2022 走看看