Java异常
1、什么是异常
异常(Exception)指程序运行过程中出现的不期而至的各种状况。如:非法传参、内存溢出、文件找不到、网络连接失败等。
- (在Java等面向对象的编程语言中)异常本身是一个对象,产生异常就是产生了一个异常对象。
2、异常的体系结构
Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的父类。
在Java的API中已经定义了许多异常类。这些异常类分为错误(Error)和异常(Exception)两大类。
2.1、错误(Error)
- Error类对象由Java虚拟机生成并抛出。
- 编译时被忽略,运行时可能会报错(抛出Error)。
- Error通常是灾难性的致命错误,是程序无法控制和处理的,如
- OutOfMemoryError
- ThreadDeath
- 这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
2.2、异常(Exception)
- Exception是程序本身可以处理的异常,这种异常分运行时异常和非运行时异常两大类。
- 程序书写过程中应当尽可能地去处理这些异常。
(1)运行时异常
-
RuntimeException(运行时异常)是Exception的一个重要分支。如:
- ArrayIndexOutOfBoundsException(数组下标越界)
- NullPointerException(空指针异常)
- ArithmeticException(算术异常)
- MissingResourceException(丢失资源)
- ClassNotFoundException(找不到类)
-
运行时异常又称不检查性异常(Unchecked Exception)。
-
编译时被忽略,运行时可能会报错(抛出Exception)。
-
程序书写过程中程序员可以选择捕获处理,也可以不处理。
-
这些异常一般是由程序逻辑错误引起的,程序员应该从逻辑角度尽可能避免这类异常的发生。
(2)非运行时异常
-
非运行时异常是RuntimeException以外的异常。 如:
- IOException
- SQLException
- 用户自定义的异常
**注:**一般情况下,我们不需要自定义异常。
-
非运行时异常又称检查性异常(Checked Exception)。
-
从程序语法角度来讲,非运行时异常是必须进行处理的异常,如果不处理,编译时就报错(抛出Exception)。
3、Java异常处理机制
在 Java 应用程序中,异常处理机制为:
-
使用try-catch-finally捕获异常。
-
使用throw或throws抛出异常。
示例程序:
1 | package com.atangbiji; |
由于被除数不能为0,所以上述程序在运行时会抛出ArithmeticException异常。运行结果如下图所示:
3.1、捕获异常
Java中使用try-catch-finally捕获异常。其中:
- **try:**监控可能出现异常的代码块。
- catch:若出现异常,则捕获相应的异常。其中的参数是想要捕获的异常类型,如:Throwable、Error、Exception、ArithmeticException 等。
- **finally:**主要处理善后工作。无论监控代码块是否出现异常,都会执行finally中的代码。
执行流程:
- 我们将可能产生异常的代码放入try块当中,当try块中代码没有异常发生时,catch块中的内容不会被执行,而直接执行之后的代码。
- 当try块发生异常时,会产生一个异常对象且当该类型能与catch块中的异常类型正常匹配时,程序就会进入到catch块执行相应的处理逻辑,然后顺序执行下去。
- 当出现异常且无法正常匹配处理则程序中断运行。
如:
1 | package com.atangbiji; |
运行结果:
捕获到程序出现的ArithmeticException异常,分母不能为0!
无论监控代码块是否出现异常,都会执行finally。
注:
-
一个try语句必须至少有一个catch语句块或一个finally语句块。
-
当异常处理的代码执行结束以后,不会回到try语句去执行尚未执行的代码。
-
每个try语句块可以伴随多个catch语句,用于处理可能产生的不同类型的异常对象,且我们必须先处理特殊类型的异常,再处理一般类型的异常(如:先处理Error异常再处理Throwable异常)。
-
同if-else if语句一样,无论try语句后面有多少个catch语句,程序只能捕获第一个出现的异常。
-
无论异常是否发生,即使try和catch块中存在return语句,finally都必须要执行。
-
finally语句块只有在一种情况下是不会执行的,那就是在执行finally之前遇到了System.exit(0)结束程序运行。
-
我们可以先选中代码块,然后使用“Ctrl+Alt+T”快捷键快速生成捕获异常的代码。
3.2、抛出异常
Java中我们也可以使用throw或throws主动抛出异常。其中:
1、throw:
- 用在方法体内。
- 抛出的是一个异常类的对象。
- 只能抛出一个异常对象。
- 当执行到throw语句时,程序会立即停止。
- 如果要捕捉throw抛出的异常,则必须使用try-catch语句块或者try-catch-finally语句。
如:
1 | package com.atangbiji; |
运行结果:
捕获到程序出现的ArithmeticException异常,分母不能为0!
无论监控代码块是否出现异常,都会执行finally。
2、throws:
- 用在方法的声明处(参数列表之后,方法体之前)。
- 后面跟的是异常的类型。
- 可以抛出多个不同类型的异常,使用逗号分隔。
- 表示此处不处理异常,交由方法调用处处理,也就是向上抛出异常。
如:
1 | package com.atangbiji; |
运行结果:
捕获到程序出现的ArithmeticException异常,分母不能为0!
无论监控代码块是否出现异常,都会执行finally。
注:
- 使用throw主动抛出的异常,是必须要捕获的(Java内置的异常JVM可以帮我们捕获,自定义的异常我们必须自己捕获)。
- 我们既可以在throw后立即捕获异常;也可以暂不处理并使用throws向上抛出异常,交由方法调用处捕获(欠的债迟早都是要还的)。
4、自定义异常(不常用)
Java中内置的异常类已经可以描述编程时可能出现的大部分异常。当然,用户也可以自定义异常。
用户自定义异常类,只需继承Exception类即可。
如:自定义一个输入非正整数的异常类
1 | package com.atangbiji; |
由于输入的数字为 -1,所以运行结果为:
5、经验总结
-
对于运行时异常,我们在采用合理的逻辑去规避它的同时,应使用try-catch语句进行处理。
-
在多重catch块后面,我们可以加一个catch(Exception e),来处理可能被遗漏的异常。
-
对于不确定的代码,我们也可以加上try-catch语句,来处理潜在的异常。
-
尽可能地去处理异常,尽量不要只是简单地调用系统默认生成的e.printStackTrace()打印输出异常,进而避免程序中断。
-
具体如何处理异常,要根据不同的业务需求和异常类型来决定。
-
尽量添加finally语句块去释放占用的资源(如:IO流中的异常等)。
(本讲完,系列博文持续更新中…… )
关注**“阿汤笔迹”** 微信公众号,获取更多学习笔记。
原文地址:http://www.atangbiji.com/2020/12/24/exception
博主最新文章在个人博客 http://www.atangbiji.com/ 发布。