你写的代码编译时是否经常报错?来看看这篇文章帮你解决大部分问题。(Java中的异常)

你写的代码编译时是否经常报错?来看看这篇文章帮你解决大部分问题。(Java中的异常),第1张

你写的代码编译时是否经常报错?来看看这篇文章帮你解决大部分问题。(Java中的异常)

目录

异常的概念与体系结构

概念

常见的异常

异常的体系结构

异常的分类

异常的处理

防御式编程  

异常的抛出

异常的捕获

异常声明(使用关键字throws)

try-catch捕获处理

关键字finally  

异常的处理流程


异常的概念与体系结构 概念

异常简单理解就是不正常,Java中的异常就是程序在执行过程中出现不正常的行为称之为异常

常见的异常

1. 算数异常(常见的是除数为0)

 System.out.println(10/0);
//执行结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero

2.数组越界异常

        int[] arr = {1,2,3};
        System.out.println(arr[10]);
//执行结果:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10

3. 空指针异常

 int[] arr = null;
 System.out.println(arr.length);
//执行结果:
Exception in thread "main" java.lang.NullPointerException

从上述例子可以看出:不同的异常对应的异常描述不同,也就是每个异常都有对应的类来进行描述。

异常的体系结构

异常的种类非常的多,为了易于区分和管理,Java内部维护了一个异常的体系结构。见下图:

对上面图进行说明:

1.Throwable:是异常的顶层类,其派生出两个子类:Error和Exception

2. Error:指的是Java虚拟机无法解决的问题,此类问题比较严重,例如:JVM内部错误,资源耗尽等,典型代表:StackOverflowError和OutOfMemoryError,该类异常一但发生,就无法解决,就像人得了癌症。

3.Exception:该类异常产生后可由程序员进行分析及处理,使得程序继续运行,就比如我们人感冒咳嗽一样。

异常的分类

因为异常发生的时机是不一样的,我们根据此将异常分为:编译时异常,运行时异常。

1. 编译时的异常

它指的是在程序编译期间发生的异常,也可称之为受检查异常(Checked Exception)

2. 运行时的异常

它指的是在程序执行期间发生的异常,也称之为非受检查异常(Unchecked Exception)

RuntimeException以及其子类对应的异常都称为运行时异常,例如:NullPointerException等

注意:编译时出现的语法错误不能称为异常,比如将某个单词拼写错误,此时编译过程中就会出错,这是“编译期”出错,而运行时异常指的是,编译已经完成得到class文件,再由JVM执行过程中出现的错误。

异常的处理 防御式编程  

1.LBYL:Look Before You Leap :指的是在对代码进行 *** 作之前做充分的检查,即:事前防御  

例:

 boolean ret = false;
      ret = 登录游戏();
      if(!ret){
          处理登录游戏错误;
          return;
      }
      ret = 开始匹配();
      if(!ret){
          处理匹配错误;
          return;
      }
      ret = 游戏确认();
      if(!ret){
          处理游戏确认错误;
          return;
      }
        ......

这种处理方式的缺陷:正确的流程和处理错误的流程混在一起了,整体比较混乱,不易阅读

2.EAFP:It's Easier to Ask Forgiveness than Permission.指的是先进行 *** 作,遇到了问题在处理,即:事后认错型

  try{
            登录游戏();
            开始匹配();
            游戏确认();
            ......
        }catch(登录游戏异常){
            处理登录游戏异常;
        }catch(开始匹配异常){
            处理开始匹配异常;
        }catch(游戏确认异常){
            处理游戏确认异常;
        }
        ......

优势:正常和错误流程分开,代码清晰,易于阅读理解

异常处理的5个主要关键字:throw  try  catch  final  throws

异常的抛出

在写程序时,如果程序出现错误,就要将错误的信息告诉给调用者,在Java中,借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者,具体语法如下:

throw new XXXException("异常产生的原因");

 举一个数组传参的例子进行说明:

public static int getElement(int[] array,int index){
        if(null==array){
            throw new NullPointerException("传递数组为null");
        }
        if(index<0||index>=array.length){
            throw new ArrayIndexOutOfBoundsException("传递的数组下标越界");
        }
        return array[index];
    }
    public static void main(String[] args) {
        int[] array = {1,2,3};
        getElement(array,3);
    }

    运行结果:
  Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 传递的数组下标越界

注意事项:

1.throw必须写在方法体内部

2. 抛出的对象必须是Exception或者Exception的子类对象

3. 如果抛出的是RuntimeException或者它的子类,可以不用处理,JVM会帮我们处理

4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译

5. 异常一旦抛出,其后的代码就不会执行

异常的捕获

异常的捕获也就是异常的具体处理方式,主要有两种:用throws进行异常声明以及try-catch捕获处理。

异常声明(使用关键字throws)

当程序抛出编译时异常时而且用户不想处理该异常,就可以借助throws将异常抛给方法的调用者来处理。

语法格式:

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

注意事项:

1. throws必须跟在方法的参数列表之后

2. 声明的异常必须是Exception或者其子类

3. 方法内部如果抛出多个异常,throws之后跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,则直接声明父类即可

4.调用抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出

try-catch捕获处理

throws对异常并没有处理,而是交给调用者处理,如果要对异常真正进行处理,就需要用try-catch

语法格式:

try{
    //这里为可能出现异常的代码
 }catch(要捕获的异常类型 e){
    //当抛出异常与catch捕获异常类型相同时,异常就会被捕获到
     //对异常进行处理完后,会跳出try-catch,继续执行后序代码
 }[catch(异常类型 e){
    //对异常处理
}finally{
    //此处代码一定会被执行
 }]
 //后序代码,异常被捕获处理了,后序代码就一定会执行
 //异常没有捕获到,后序代码就不会执行

注意:[  ]中表示可选项,可以添加,也可以不添加

关于异常的处理方式:

1.异常的种类非常多,我们要根据不同的场景环境来决定

2. 对于更严重的问题(例如栈相关场景),应该让程序直接崩溃,防止造成更严重的后果

3.对于不太严重的问题,可以记录错误日志,并通过监控报警及时通知程序员

4. 对于可能会恢复的问题(网络相关场景),可尝试进行重试

注意事项:

1. try块内抛出异常位置之后的代码将不会被执行

2. 如果抛出异常类型与catch内的异常类型不匹配,即异常不会被成功捕获,也不会被处理,继续往外抛,直到JVM收到后中断程序---异常是按照类型来捕获的

3. try中可能会抛出多种类型异常,则必须用多个catch来捕获多种类型

4. 如果异常之间具有父子关系,一定是子类异常的catch在前,父类异常的catch在后,否则语法错误

由于Exception是所有异常类的父类,所以可以用这个类型表示捕捉所有异常

关键字finally  

在写代码时,有些特定的代码无论程序是否发生异常都需要执行,比如程序中的打开资源,网络连接,数据库连接,IO等,在程序正常或者异常退出时,必须要对资源进行回收,另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这一问题的。

语法格式:

  try{
       //可能发生异常的代码 
    }catch(异常类型 e){
        //对捕获的异常进行处理
    }finally{
      //这里的代码无论异常是否被捕获到,都会执行  
    }
    //如果没有异常或者异常被捕获处理了,这里后序的代码也执行

举数组的例子进行说明:

  public static void main(String[] args) {
        try{
            int[] array = {1,2,3};
            array[10] = 10;
            array[0] = 10;
        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println(e);
        }finally{
            System.out.println("这里代码一定执行");
        }
        System.out.println("如果没有异常,或者异常被捕获处理,这里代码也将执行");
    }

执行结果:
java.lang.ArrayIndexOutOfBoundsException: 10
这里代码一定执行
如果没有异常,或者异常被捕获处理,这里代码也将执行

这里存在了一个问题:既然finally和try-catch-finally后的代码都会执行,为什么还要有finally的?看完下面的代码,这个问题那就会迎刃而解。

public static int getData(){
        Scanner sc = null;
        try{
            sc = new Scanner(System.in);
            int data = sc.nextInt();
            return data;
        }catch(InputMismatchException e){
           e.printStackTrace();
        }finally{
            System.out.println("finally中的代码");
        }
        System.out.println("try-catch-finally之后的代码");
        if(null!=sc){
            sc.close();
        }
        return 0;
    }
    public static void main(String[] args) {
        int data = getData();
        System.out.println(data);
    }
输入:10
运行结果:
finally中的代码
10

上述程序,正常输入,return data后,方法就结束了,try-catch-finally后的代码根本没有执行,即输入流没有释放,造成资源泄露。

注意:finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作。

如果finally中也存在return语句,则执行finally中的return语句,就不会执行try中的return语句

异常的处理流程

1. 程序先执行try中的代码

2. 如果try中的代码出现异常,就会结束try中的代码,与catch中的异常类型是否匹配

3. 如果找到匹配的异常类型,就会执行catch中的代码

4.如果没有找到匹配的类型,就会将异常向上传递到上层调用者

5. 无论是否找到匹配的异常类型,finally中的代码都会被执行到(在该方法结束之前执行)

6.如果上层调用者也没有处理异常,就会继续向上传递,一直到main方法也没有合适的代码处理异常,就会交给JVM来进行处理,此时程序就会异常终止

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/4996077.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-14
下一篇 2022-11-14

发表评论

登录后才能评论

评论列表(0条)

保存