Java 超详细讲解异常的处理

 更新时间:2022年04月02日 10:36:42   作者:Pretend..  
异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

1、异常的概念和体系结构

1.1异常的概念

Java中,在程序执行过程中发生的不正常行为称为异常。比如之前一直遇到的:

(1)算数异常

System.out.prinntln(10/0);

(2)数组越界异常

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

(3)空指针异常

int[] arr=null;
System.out.println(arr.length());

1.2异常的体系结构及分类

  • Throwable:是异常体系的顶尖层,派生出两个钟要的子类:而Error、Exception
  • Error:指的是Java虚拟机无法解决的严重问题
  • Exception:就是我们平常所说的异常。程序员可以以通过代码进行处理,使程序继续执行。

【异常的分类】

  • 运行时异常(受查异常):RuntimeException下的所有异常为运行时异常
  • 编译时异常(非受查异常):IOException、ClassNotFoundException、CloneNotSupportedException为编译时异常

【注】编译时出现的语法错误,不能称之为异常。运行时指的是程序已经编译通过得到class文件了,再由JVM执行过程中出现的错误。

2、异常的处理

在Java中,异常处理主要的五个关键字:throw、try、catch、final、throws

2.1防御式编程

(1)LBYL:look before you leap,在操作之前就做充足的检查(事前防御型)

boolean ret=false;
ret=登陆游戏();
if(!ret){
    处理登陆游戏错误;
    return;
}
ret=开始匹配();
if(!ret){
    处理匹配错误;
    return;
}
………………

缺陷:正常流程和错误处理代码混在一起,代码整体显得比较混乱。

(2)EAFP:it is easier to ask forgiveness than permission,先操作,遇到问题再解决。(事后认错型)

try{
   登陆游戏();
   开始匹配();
}catch(登陆游戏异常){
    处理登陆游戏异常;
}catch(开始匹配异常){
    处理匹配异常;
}

2.2异常地抛出

在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];
    }

【注】

  • throw必须写在方法的内部
  • 抛出的对象必须是Exception或Exception的子类对象
  • 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
  • 如果抛出的是RuntimeException或其子类,可以不用处理,直接交给JVM来处理
  • 异常一旦抛出,后面的代码不会再执行

2.3异常的捕获

异常的具体处理方式,主要有两种:异常声明throws和try-catch捕获处理

printStackTrace()打印异常

(1)异常声明throws

当前方法不处理异常,提醒方法的调用者处理异常。

语法格式:

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

【例】加载指定的配置文件

public class Config {
        File file;
        /*
        FileNotFoundException : 编译时异常,表明文件不存在
        此处不处理,也没有能力处理,应该将错误信息报告给调用者,让调用者检查文件名字是否给错误了
        */
        public void OpenConfig(String filename) throws FileNotFoundException {
            if(filename.equals("config.ini")){
                throw new FileNotFoundException("配置文件名字不对");
            }
        // 打开文件
        }

【注】

  • throws必须跟在参数列表的后面。
  • 声名的异常必须是Exception或Exception的子类。
  • 方法的内部如果抛出多个异常,throws后面必须跟多个异常类型,用逗号隔开。如果抛出的异常之间有父子关系,直接声明父类异常即可。
  • 调用声明抛出异常的方法时,调用者必须对异常进行处理,或者继续使用throws。

(2)try-catch捕获并处理

throws并没有对异常真正处理,而是将异常报告给异常方法的调用者。如果真正要对异常进行处理,需要try-catch。

【语法如下】

try{
    // 将可能出现异常的代码放在这里
}catch(要捕获的异常类型 e){
    // 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型一致时,或者是try中抛出异常的父类时,就会被捕获到
    // 对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码
}【catch(异常类型 e){
    // 对异常进行处理
}finally{
    // 此处代码一定会被执行到
}】
// 后序代码
// 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行
// 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行

注意: 
1. 【】中表示可选项,可以添加,也可以不用添加 
2. try中的代码可能会抛出异常,也可能不会

【注意】

  • try块中抛出异常位置后的代码不会被执行
  • 如果抛出异常类型与catch类型不匹配,即异常不会被成功捕获,则需要JVM来处理异常------异常是按照类型来捕获的。
  • rey中可能会抛出多个不同的异常对象,必须用多个catch来捕获。
  • 如果异常之间有父子类关系,必须子类异常在前catch,父类异常在后catch,否则语法错误。
  • 可以通过一个catch来捕获多个异常(不推荐)。

由于Exception类是所有异常的子类,因此可以用这个类型来捕捉所有异常。catch进行类型匹配时,不光会匹配相同类型的异常对象,也会捕捉目标异常类型的子类对象。

(3)finally

在写程序时,有些特定的代码,无论程序是否发生异常,都需要执行,比如程序正常打开的资源,有时候必须对资源进行回收。另外,异常会引发程序的跳转,可能导致有些语句执行不到,此时需要finally来解决这个问题。

【语法格式】

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

【问题】既然finally和try-catch-finally后的代码都会被执行,那为什么还要有finally呢?

当catch没有捕获到异常时,此时需要JVM来捕获异常,程序可能不能正常运行,finally后面的代码就不会被执行。而finally中的代码一定会被执行。

【注】finally中的代码一定会被执行,一般在其中进行资源清理的扫尾工作。

如下代码:

public static int func(){
   try{
      return 10;
   }finally{
      return 20;
   }
}
//此时返回20;

finally执行的时机是方法返回之前(try或者catch中如果有return会在return之前执行finally)。但是如果finally中也存在return语句,那么就会执行finally中的return,从而不会执行到try中原有的return。

2.4异常的处理流程

关于“调用栈”:

方法之间存在相互调用的关系,可以用“调用栈”来描述。在JVM中有一块内存空间称之为:“虚拟机栈”专门存储方法之间的调用关系。当代码中出现异常的时候,我们就可以使用e.printStackTrace();的方法查看出现异常代码的调用栈。

如果本方法中没有合适的处理异常的方法,就会沿着调用栈向上传递,如果一直向上传递都没有找到合适的方法,最终会交给JVM来处理,程序就会异常终止。

【程序异常处理的流程】

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

3、自定义异常类

具体方法:

  • 自定义异常类,然后继承自Exception或者RunTimeException。
  • 实现一个带有String类型参数的构造方法。
class UserNameException extends Exception {
    public UserNameException(String message) {
        super(message);
    }
}

【注】

  • 自定义异常通常会继承自Exception或者RunTimeException。
  • 继承自Exception的异常默认为受查异常。
  • 继承自RunTimeException的异常默认为非受查异常。

到此这篇关于Java 超详细讲解异常的处理的文章就介绍到这了,更多相关Java 异常内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 数据结构与算法之并查集(不相交集合)

    数据结构与算法之并查集(不相交集合)

    并查集是一种挺高效的数据结构。实现简单,只是所有元素统一遵从一个规律所以让办事情的效率高效起来。这篇文章主要介绍了数据结构与算法——并查集(不相交集合),需要的朋友可以参考下
    2019-11-11
  • springboot+vue实现验证码功能

    springboot+vue实现验证码功能

    这篇文章主要为大家详细介绍了springboot+vue实现验证码功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • java 实现当前时间加减30分钟的时间代码

    java 实现当前时间加减30分钟的时间代码

    这篇文章主要介绍了java 实现当前时间加减30分钟的时间代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • MyBatis批量插入的五种方式

    MyBatis批量插入的五种方式

    这篇文章主要介绍了MyBatis批量插入的五种方式,每种方式结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-11-11
  • 使用spring data的page和pageable如何实现分页查询

    使用spring data的page和pageable如何实现分页查询

    这篇文章主要介绍了使用spring data的page和pageable如何实现分页查询,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Java 实例解析单例模式

    Java 实例解析单例模式

    单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建
    2021-11-11
  • Java中String性能优化

    Java中String性能优化

    本文给大家分享的是如何在java中对String进行性能优化,使用String的时候需要有哪些注意事项呢,这就是今天我们要给大家总结分析的,有需要的小伙伴可以参考下。
    2015-03-03
  • Java用POI解析excel并获取所有单元格数据的实例

    Java用POI解析excel并获取所有单元格数据的实例

    下面小编就为大家带来一篇Java用POI解析excel并获取所有单元格数据的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • 一问详解SpringBoot配置文件优先级

    一问详解SpringBoot配置文件优先级

    在SpringBoot项目当中,我们要想配置一个属性,可以通过这三种方式当中的任意一种来配置都可以,那么优先级怎么算,本文主要介绍了一问详解SpringBoot配置文件优先级,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Java之SpringBoot实现基本增删改查(前后端分离版)

    Java之SpringBoot实现基本增删改查(前后端分离版)

    这篇文章主要介绍了Java中SpringBoot如何实现基本的增删改查,前后端分离版,没有和前端进行联系,感兴趣的小伙伴可以借鉴阅读本文
    2023-03-03

最新评论