java异常处理-程序员宅基地

技术标签: jvm  青少年编程  javaSE  开发语言  

目录

一、什么是异常

二、异常处理

        1、如何捕捉异常?

        2、finally语句

        3、finally语句中的throw和return 

三、常见异常

四、自定义异常

        那么具体如何自定义异常类呢?

        throw关键字

        throws关键字

五、运行时异常

六、异常处理流程 

‍️‍️多多支持




前言:

        在程序设计和运行的过程中,发生错误是不可避免的。为此java提供了异常的处理机制,来帮助程序员检查可能出现的错误。保证程序的可读性和可维护性。java将异常封装到一个类中,出现错误时就会抛出异常,程序终止。

 通过学习,您可以了解到:

1、什么是异常
2、如何捕捉异常
3、java中有哪些常见的异常
4、如何自定义异常
5、如何在方法中抛出异常
6、运行时有哪些异常
7、异常处理的使用原则




一、什么是异常

        错误产生于没有实现预料到的各种情况,或是超过了程序员可控制范围的环境因素。
就比如我们经常遇到的遇到除数为0的情况,但是自身又没发现,于是程序运行到这一样是就会让程序异常终止:

① 算术异常 

        程序运行时发生了算数异常ArithmeticException,根据异常提示可以知道是在Test2的main方法中发生了算术异常,异常为 / by zero,意为0被作为了除数而报错。

         可以看到,异常前的程序都会正常执行,当执行到异常,系统就不会再执行下去,提前结束并提示:程序异常退出

Process  finished  with  exti  code  1

异常类为ArithmeticException

        还有很多例子,例如

②数组越界:

        代码案例: 

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{0,1,2,3,4,5};
        System.out.println(arr[6]);
    }
}

         运行结果:

 异常类为ArrayIndexOutOfBoundsException

③空引用的使用空指针):

        代码案例:

public class Main {
    public static void main(String[] args) {
        String tem = null;
        int stringLength = tem.length();
        System.out.println(stringLength);
    }
}

        执行结果:

 异常类为NullPointerException

        java是面向对象的计算机语言,所以在java中异常都是作为类的实例的形式出现的。当某一方法中发生错误时,这个方法会创建一个对象,并且把它传递给正在运行的系统。   这个对象就是异常对象,通过异常处理机制,可以将非正常情况下的处理代码与程序的主逻辑分离,即在编写代码主流程时在其他地方处理异常。

        这些异常种类和异常处理机制将会在下面的篇章中逐渐渗透。




二、异常处理

        为了保证程序能正常的运行,我们需要对出现的异常错误进行及时的处理。在java 的异常处理机制当中,当某个方法出现异常时,可以在该方法里进行捕捉,然后处理异常,也可以将异常向上抛出,交给该方法的调用者处理。

        如果对产生的异常不做任何的处理,程序就会异常终止。所以需要对该异常进行捕捉然后处理。

        1、如何捕捉异常?

        java语言的异常捕捉结构为:

try{

        // 可能产生异常错误的语句

}catchExceptionTypeOne  e){

        // 对异常 ExceptionTypeOne 的处理语句

}catch ( ExceptionTypeTwo e) {

        // 对ExceptionTypeTwo 的处理语句

}

...........

finally {

        // 语句块

}

此结构由 trycatch finally  3部分组成。其中:
①  try语句中的是可能发生异常的代码
②  catch用来捕捉异常,{}中为异常处理的语句
③  finally为异常处理的最后执行部分,无论前面的catch是否被捕捉,finally语句都会被执行

其中的  Exception 是try代码块传递给catch代码块的变量类型,e是变量名。

         我们使用这种try -  catch语句来对上面的 / by zero异常来进行一个修改:

public class Test2 {
    public static void main(String[] args) {
        try {
            int digit = 1;
            int zero = 0;
            System.out.println("value of digit is:"+digit);
            System.out.println("value of zero is:"+zero);
            int result = digit / zero;
            System.out.println("value of result is:" + result);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("hello world!");
    }
}

        catch代码块中的语句e.printStackTrace() 语句时用于输出错误性质,通常,异常处理用下面三个函数来获取异常有关信息:

getMessage()   // 输出错误性质

toString() // 给出一场的性质和类型

printStackTrace() // 指出异常类型、性质、栈层次及出现在程序的位置

运行结果如图:

        可以发现,digit 和 zero 的值都被打印,但是result的值没有被打印,try - catch 语句外的打印
hello world 的语句也被打印。紧接着的一行就是  Process finished  with  exit  code  0 
表示程序正常退出。

        当有多个catch 语句的情况:



public class Main {
    private static int Test(int x, int y) throws MyException{
        if(y < 0){
            throw new MyException("除数不能为负数");
        }
        return x/y;
    }
    public static void main(String[] args) {
        try {
            int ret = Test(2,-1);
        } catch (MyException e) {
            System.out.println(e.getMessage());  // 进行捕捉
        } catch (ArithmeticException e){
            System.out.println(e.getMessage());
        } catch (Exception e){
            System.out.println("发生了其他异常");
        }
    }
}

        上面实例使用了很多个catch语句来捕捉异常, 其中

① 调用Test (2 , -1 ) 将会发生MyException异常,进而转入catch (MyException e)执行

② 调用Test (3 , 0) 将会发生ArithmeticException异常,转入对应的catch语句执行

③  如果还有除了 0 和 负数之外的异常,那么将会被Exception e捕捉然后转入catch语句执行

但是由于  Exception是所有异常类的父类,如果将其与MyException调换位置如果图:

 那么 前面的 ArithmeticException异常和 MyException 异常都会被 第一个catch语句捕捉,
那么后面的catch语句就不会执行,最后就只会收到一个发生了其他异常的字符串提示,对于异常的处理没有任何的帮助,try - catch语句也就是去了它的意义。

        通过try - catch 语句,程序没有异常退出,而是将错误抛出后,继续执行try  -  catch 异常捕捉后面的语句,而不至于因为一个异常从而影响整个程序的运行

        2、finally语句

        一个完整的try  -  catch 语句一定要包含finally语句无论程序是否有异常发生,并且无论之间的try -  catch语句是否顺利执行完毕,都会执行finally语句
        但是也存在意外,finally语句不会被执行的情况,如下:

① 在finally 语句中发生了异常

② 在前面的代码中使用了System.exit()语句,程序提前结束

③ 程序所有的线程死亡

④ 关闭CPU

        3、finally语句中的throw和return 

无论有没有异常都会执行finally语句,那么如果在try-catch语句块中遇到了return和throw语句,后面的finally语句是否还会执行呢?代码案例如下:

public class Test { 
    public static void main(String[] args) { 
        System.out.println("return value of getValue(): " +
        getValue()); 
    } 
     public static int getValue() { 
         try { 
             return 0; 
         } finally { 
             return 1; 
         } 
     } 
 }

 程序的运行结果是什么?

解析:当Java程序执行ty块、catch块时遇到了retun语句, 并不会立马结束这个方法,而是去寻找该异常处理流程中是否包含finally语句块,如果没有finally块,方法终止,返回相应的返回值。如果有finally块, 系统立即开始执行finally块中的语句,只有当finally块执行完成后,系统才会再次回到try-catch语句中来根据return语句结束方法。如果finally块里使用了return语句,则finally块会直接执行return语句并返回,使方法结束,系统将不会跳回去执行try块、 catch块里的任何代码。

结果如下:

 return value of getValue(): 1




三、常见异常

        java内部提供了一些异常,用来描述经常发生的错误,其中,有的需要程序员极性捕捉处理或声明抛出。有的是由java虚拟机自动进行捕捉

        java常见的异常类如表:

java常见的异常类
异常类 说明
ClassCastException 类型转换异常
ClassNotFoundException 未找到相应的类异常
ArithmeticException 算术异常
ArrayIndexOutOfBoundsException 数组下标越界异常
ArrayStoreException 数组中包含不兼容的值抛出的异常
SQLException 操作数据库异常类
NullPointerException 空指针异常
NoSuchFieldException 未找到字段异常
NoSuchMethodException 方法未找到抛出的异常
NumberFormatException 字符串转化为数字抛出的类异常
NegativeArraySizeException 数组元素个数为负数抛出的异常
StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
IOException 输入输出异常
IllegalAccessException 不允许访问某类异常
InstantiationException 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常
EOFException 文件已结束异常
FileNotFoundException 文件未找到异常

         以上异常的出现场景希望读者可以自行研究。




四、自定义异常

        使用java内置的异常类可以处理在编程期间出现的大多数异常情况,但是仍有部分比较有特性的异常是java内置异常没有覆盖到的。例如:对于需要传入整数的一个方法,你可能会觉得,传入 一个负数是不符合你的期望,认为负数作为这个方法的参数为一个错误的值,但是对于java来说,它不会将其视为一个错误或者异常。

        所以为了能个性化地去解决这些在特殊情况才能出现的异常,java引入了自定义异常类,用户只需要继承Exception类即可以自定义异常类。

        那么具体如何自定义异常类呢?

① 首先,在java中异常都是作为类的实例的形式出现的,所以我们应该先定义自定义的类,类名设为MyException(自定义类名视使用场景况而定),然后由该类继承Exception类:

        代码案例:

public class MyException extends Exception{    // 声明这个MyException类并让其继承Exception类
    public MyException (String ErrorMessage){    // 调用构造方法
        super(ErrorMessage);   // 给父类Exception传参
    }
}

        字符串ErrorMessage是要输出的错误信息。

使用throw关键字,在需要的时候抛出异常,就比如我们经常使用ArrayList表里面的set方法:

 里面就是使用了rangeCheck()方法来检查index是否越界,点击查看rangeCheck方法可以看到如下:

 在这里通过使用throw 关键字抛出对应的异常信息,里面的outOfBoundMsg(index)返回一个错误 的异常信息的字符串,对应我们自定义异常的  ErrorMessage  :

         然后使用构造方法构造new 出一个IndexOutOfBoundsException 的实例并抛出异常。

        我们使用自定义异常配合try- catch语句来模拟这个过程:
 



public class Main {
    private static void checkMySet(int pos,int len) throws MyException{
        if(pos >= len){
            throw new MyException("指定的下标超过已有的最大下标位置");
        } else if (pos < 0 ) {
            throw new MyException("指定下标小于0!");
        }else {
            System.out.println("下标数值正确!");
        }
    }
    public static void set(int[] arr,int pos,int element) throws MyException {
        checkMySet(pos,arr.length);
        arr[pos] = element;
    }
    public static void main(String[] args) {
        int[] arr = new int[10];
        try {
            set(arr,-4,10);   // 可能抛出异常
        } catch (MyException e) { 
            System.out.println(e);  // 进行捕捉
        }
    }
}

结果为:

程序正常退出。 

        throw关键字

        throw关键字通常用于方法体重,并且抛出一个异常的实例化对象,对象被抛出后程序终止:

 可以看到,如果在方法体内抛出对象的语句后面加上语句,那么后面的语句将永远不会执行到

代码案例如下:

public class Main {
    private static void Test(int pos) throws MyException{
        if(pos >= 0){
            throw new MyException("pos >= 0");
        }
        System.out.println("checkEnded");
    }
    public static void main(String[] args) {
        int[] arr = new int[10];
        try {
            System.out.println("TestStart");
            Test(0);
            System.out.println("TestEnd");
        } catch (MyException e) {
            System.out.println(e);  // 进行捕捉
        }
    }
}

 执行结果:

 可以看出来,在方法抛出异常后,该方法后面的语句也不会执行

如果要捕捉异常,就必须使用try - catch语句

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

        throws关键字

        throws关键字通常被用来在声明方法的时候,指定其方法可能抛出的异常,多个异常可以用“,”逗号分割:

public static void Test ()  throws  Exception1 , Exception2 , Exception3 {

        //可能会抛出Exception1 , Exception2 , Exception3异常的方法体

}

        从上面的代码案例中我们可以看到:checkMySet()方法中加入了if 语句来来判断是否抛出异常,有可能会抛出,也可能不会抛出,只要有抛出的可能,就需要在其方法后用throws关键字声明可能会抛出的异常类。

        处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws 将异常抛 给方法的调用者来处理。

        异常被throws 不断向上抛出,最终被catch 捕获并处理。

需要注意的是: 

throws必须跟在方法的参数列表之后
② 声明的异常必须是 Exception 或者
Exception 的子类




五、运行时异常

        RuntimeException 异常是程序运行过程中产生的异常。它是Exception类的子类之一。

         java类库的每个包中都定义了异常类,所有的类都是Throwable的子类,Throwable派生出两个子类,分别是Exception 和 Error 类。 Error 类及其子类用来描述java运行系统中的内部错误以及资源消耗的错误。

        Exception类异常通过捕捉后程序可以继续正常执行。

 

 其中RuntimeException的异常种类

         从图中可以看出来,Throwable 是异常处理体系的顶层类,派生除了Error 和 Exception 两个重要的子类。Error 指的是java虚拟机无法解决的严重问题,例如jvm内部错误,资源耗尽等等,其代表为: StackOverflowError  和 OutOfMemoryError

        Exception 异常类为程序员可以正常捕捉并处理的异常。

RuntimeException异常
NullPointerException 空指针异常
ArrayIndeOutOfBoundsException 数组下标越界异常
ArithmeticException 算术异常
SecurityException 安全性异常
NegativeArrayException 数组长度为负异常
IllegalArgumentException 非法参数异常
ArrayStoreException 数组中包含不兼容参数异常




六、异常处理流程 

        程序先执行 try 中的代码 如果 try 中的代码出现异常 , 就会结束 try 中的代码 , 看和 catch 中的异常类型是否匹配 . 如果找到匹配的异常类型, 就会执行 catch 中的代码 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者 . 无论是否找到匹配的异常类型, fifinally 中的代码都会被执行到 ( 在该方法结束之前执行 ). 如果上层调用者也没有处理的了异常, 就继续向上传递 . 一直到 main 方法也没有合适的代码处理异常 , 就会交给 JVM 来进行处理 , 此时程序就会异常终止。
        
        java异常强制用户去考虑程序的强健性和安全性。当程序运行到某个方法可能会出现异常时,可以在当前方法中使用try - catch 语句捕获异常。
        如果一个方法被覆盖的时候,则需要在他的上级方法中声明抛出相同异常或异常的子类。如果父类中抛出多个异常,则覆盖方法必须抛出那些异常的的一个子集,不能抛出新的异常。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/niceffking/article/details/128101122

智能推荐

eNSP综合实验合集(eNSP综合大作业合集)_可先收藏_ensp的无线网络技术大作业3000字-程序员宅基地

文章浏览阅读10w+次,点赞123次,收藏1.1k次。该文章对eNSP的综合实验做了一个归纳和总结,文章中包含了多个综合实验,可以自由的切换到相应的文章中进行查看_ensp的无线网络技术大作业3000字

【爬虫实战】python文本分析库——Gensim-程序员宅基地

文章浏览阅读2.1k次,点赞25次,收藏37次。Gensim 允许你使用 TF-IDF 权重和其他算法来提取文档中的关键词。当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。_gensim

Android分享一张图片_android 分享一张图片到basequickadapter中-程序员宅基地

文章浏览阅读1k次。public class Act_Share extends Activity { private ShareCustomAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(_android 分享一张图片到basequickadapter中

Linux所有服务开放对应端口大全_linux服务器端口全部开放-程序员宅基地

文章浏览阅读4.7k次。Linux所有服务开放对应端口大全_linux服务器端口全部开放

php连接mysql实现简单注册登陆页面_php连接数据库登录和注册-程序员宅基地

文章浏览阅读1.6w次,点赞33次,收藏226次。PHP7连接数据库的方式:使用mysqli及PDOhttps://blog.csdn.net/zwliang98/article/details/82997349php输出执行sql语句的错误信息:mysqli_query($conn,$sql) or die(mysqli_error( $conn ));问题一:Incorrect integer value: ‘’ for colu..._php连接数据库登录和注册

深度学习之——防止过拟合的方法_加噪声防止过拟合-程序员宅基地

文章浏览阅读3.2k次,点赞8次,收藏13次。1、过拟合定义:在training data上的error渐渐减小,但是在验证集上的error却反而渐渐增大——因为训练出来的网络过拟合了训练集,对训练集外的数据却不work。模型越复杂,越容易过拟合。因此,原先以最小化损失(经验风险最小化)为目标:现在以最小化损失和模型复杂度(结构风险最小化)为目标:通过降低复杂模型的复杂度来防止过拟合的规则称为正则化。2、..._加噪声防止过拟合

随便推点

Cheat Engine 修改汇编指令_ce用空指令替换原指令-程序员宅基地

文章浏览阅读6.6k次,点赞2次,收藏9次。打开游戏 扫描阳光 扫描过程就不讲了 找到阳光的地址 显示反汇编 找到使阳光减少的反汇编代码 空指令替换 将阳光减少汇编指令,用空指令替换,这样阳光就不再减少了 ..._ce用空指令替换原指令

9.10 中国电信it研发中心 笔试编程题_中国电信计算机类试卷有编程吗-程序员宅基地

文章浏览阅读1.3w次,点赞6次,收藏37次。A 题意: 假设字符串中出现次数最少的字母是x, 出现次数为y, 删除所有出现次数为y的字符 思路: 统计一下字符的出现次数, 然后照着做就行#include &amp;amp;lt;iostream&amp;amp;gt;#include &amp;amp;lt;algorithm&amp;amp;gt;#include &amp;amp;lt;string&amp;amp;gt;#include &amp;amp;lt;cmath_中国电信计算机类试卷有编程吗

数据库的分类_relative database relation database-程序员宅基地

文章浏览阅读88次。关系型数据库(RDBMS:relative database manager system)特点:(1) 表与表之间有关系(2) 有行有列(和excel类似)(3) 是通过SQL语句去操作数据库。比较有名代表:Mysql:免费,开源。Oracle:甲骨文,收费,大型公司,一年费用9位数SQL Server:微软公司,可以安装WindowsDB2非关系型数据库(no-sql)特点:(1) 表与表之间没有关系(2) 通过API(Java、PHP、Python代码)去操作(3) 充分使_relative database relation database

RxJAVA-Single_rxjava single-程序员宅基地

文章浏览阅读960次。interface SingleObserver<T> { void onSubscribe(Disposable d); void onSuccess(T value); void onError(Throwable error);}订阅者一共三个方法可以处理。给出示例package com.netty.demo.vertx;import io.reactivex.*;import io.reactivex.disposables.Disposab._rxjava single

CSR8675的DSP学习笔记——离线调试与仿真_csr adk4.2-程序员宅基地

文章浏览阅读1.2w次,点赞2次,收藏22次。写在最前面:很多读者反馈希望可以有硬件平台配合学习。现与思度科技联合推出CSR867x学习板【淘宝链接:思度科技CSR867x学习板】,进QQ群获取激活码购买学习板享受如下优惠: 1. 价格优惠 2. 免费提供开发教程和项目源码 3. 免费提供入门级技术支持QQ群号:743434463—————————–正文分割线———————————1. 引言CSR8675的DSP..._csr adk4.2

由于高精度事件计时器(HPET)驱动过时导致AMD机器装Win10的卡死蓝屏问题记录_win10关闭高精度事件计时器-程序员宅基地

文章浏览阅读1.5w次。AMD记性频繁卡死,蓝屏,特征在于:打游戏等高负载条件,电脑没有问题;闲置一定时间之后蓝屏或者死机,鼠标键盘无反应,界面全部卡死,只能按开机键重启。未保存的数据全部丢失。近日蓝屏代码 有两类,一,IRQL NOT LESS OR EQUAL 。驱动程序使用了不正确的内存地址造成。第二种是 KMODE_EXCEPTION_NOT_HANDLED。这种主要是由于过时或损坏的设备驱动程序文件。以下..._win10关闭高精度事件计时器

推荐文章

热门文章

相关标签