深入理解java的异常情况
作者:一朵花花 发布时间:2021-07-15 01:00:50
什么是异常?
在程序的运行或者编译时,所产生的错误统称为异常 (也叫Bug)
异常的存在形式
异常在java中以类的形式存在,每一个异常类都可以创建异常对象
我们平时看到的异常,都被封装成一个类
例如:0 为除数,异常为:ArithmeticException
查看在线文档会发现:
Java异常体系
异常的分类
异常分为:运行时异常 和 编译时异常
运行时异常
运行时异常又称为:非受查异常,指的是在程序运行时所抛出的异常
特点:Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过
编译时异常
编译时异常又称为:受查异常,在程序编译时的异常
是RuntimeException以外的异常,类型上都属于Exception类及其子类,从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过
错误 Error
是程序无法处理的错误,表示运行应用程序中较严重问题
错误是预测不到的,如果应用程序出现了Error,那么将无法恢复,只能重新启动应用程序
编译时异常和运行时异常的区别
编译时异常 | 运行时异常 | |
---|---|---|
发生概率 | 比较高 | 比较低 |
处理方式 | 需要在运行之前对其进行 预处理 | 没必要提前进行预处理 |
常见的异常
我们之前已经接触了一些异常,常见的异常还是有必要记住的
0为除数(算数异常)
int a = 10 / 0;
数组下标越界(数组下标越界异常)
int[] array = {1,2,3};
System.out.println(array[4]);
访问 null(空指针异常)
空指针异常出现的概率非常高!!
int[] array = {1,2,3};
array = null;
System.out.println(array[2]);
防御式编程
程序出现问题的时候及时通知程序猿,主要有两种主要的方式:
BYBL
Look Before You Leap
,在操作之前就做充分的检查
举例:一个男孩子很喜欢一个女孩子,想要拉女孩子的手,提前问:我可以拉你的手嘛?
EAFP
It's Easier to Ask Forgiveness than Permission
,“事后获取原谅比事前获取许可更容易”,也就是先操作,遇到问题再处理
举例:男孩子先拉的女孩子的手,女孩子很生气,呼了一巴掌,男孩子再回来巴拉巴拉道歉
异常的核心就是EAFP
Java处理异常的语法
异常抛出—throws
指编程人员主动抛出一个异常
任何Java代码都可以抛出异常,在方法声明的位置上使用 throws 关键字抛出,抛给方法的调用者来处理,这种处理异常的态度:上报
举例:
public static void testThrows() throws NullPointerException {
Integer p = null;
System.out.println(p + 1);
}
注意:
方法的调用者负责处理该异常
在定义方法时,把异常抛出就是为了提醒方法的使用者,有异常需要预处理
如果异常对象是 非RuntimeException,则需要在方法申明时加上该异常的抛出
即需要加上 throws 语句 或者 在方法体内 try catch 处理该异常,否则编译报错
执行到 throw 语句,后面的语句块不再执行
异常捕获—try…catch
这个异常不会上报,自行处理,异常抛到此处为止,不再上抛
try {
//可能出现异常的代码
}
catch (Exception1 e) { //参数:异常的类型 e
//捕获try当中可能出现的异常
}
catch (Exception2 e) { //参数:异常的类型 e
//捕获try当中可能出现的异常
} finally {
}
举例:
int[] array = {2,4,6,8};
try{
System.out.println(array[4]);
}
catch (ArrayIndexOutOfBoundsException e){
System.out.println("捕获到数组越界异常!");
}
对比:
注意:
try{ } 包含了可能出现异常的代码
catch 可以有一个或多个,catch中是捕获 try 当中可能出现的异常,可以通过 catch 捕获多个异常
catch 块当中,一定要捕获相应的异常,如果程序抛出的异常在 catch 块当中不能被捕获,则会交给JVM来处理异常,程序便会异常终止
当 try 中的代码出现异常时,try 里异常之后的代码不会执行,马上会跳转到相应的catch语句块中,如果没有异常便不会跳转
不管是否出现异常,finally{ } 里的代码都执行,finally和catch可以分开使用,但finally必须和try一块使用
不建议直接捕获 Exception 异常,要捕获就捕获具体的
不建议在 finally 中出现 return语句
catch 只能处理对应种类的异常
try 负责回收资源
Scanner scan = new Scanner(System.in);
try{
int n = scan.nextInt();
System.out.println(10/n);
}
catch (ArithmeticException e){
e.printStackTrace();
}
finally {
scan.close();
}
在Idea里,会发现 try 背景色会加深,将鼠标放在 try,按 Alt + Enter
出现上图,回车即可!
然后代码就会自动被优化:
即:将 Scan 对象在 try( )中创建,就能保证在 try 执行完毕后自动调用 Scanner 的 close 方法
向上传递,处理异常
先看代码:
public static void func(){
int[] array = {2,4,6,8};
System.out.println(array[4]);
}
public static void main(String[] args) {
func();
}
上述代码,func 方法里存在数组越界异常,但并没有处理,到 main 中调用 func 方法,由于 main方法里也没有处理该异常,则会交给 JVM,那么程序一运行,遇到异常,直接就会终止
改进:
public static void func(){
int[] array = {2,4,6,8};
System.out.println(array[4]);
}
public static void main(String[] args) {
try {
func();
}
catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
finally {
System.out.println("hahaha");
}
异常的传递是可以沿着栈向上传递的,方法是要在栈上开辟内存的
处理流程
程序先执行 try 中的代码
若 try 中的代码出现异常,就会结束 try 中的代码,看和 catch 中的异常类型是否匹配
若找到匹配的异常类型,就会执行 catch 中的代码
若没有找到匹配的异常类型,就会将异常向上传递到上层调用者
无论是否找到匹配的异常类型,finally 中的代码都会被执行到(在该方法结束之前执行)
若上层调用者也没有处理的了异常,就继续向上传递
一直到 main 方法也没有合适的代码处理异常,就会交给 JVM 来进行处理,此时程序就会异常终止
自定义异常类
自定义异常类步骤:
编写一个类继承 Exception 或者 RuntimeException提供两个 构造方法,一个无参数的,一个带有 String 参数的
class MyException extends RuntimeException{
//构造方法
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}
自己玩~~
public static void func(int x){
if(x == 10){
throw new MyException("x==10");
}
}
public static void main(String[] args) {
try {
func(10);
}
catch (MyException e){
e.printStackTrace();
}
}
输出结果:
注意事项:
一定要继承一个父类异常,通常是 Exception / RuntimeException
一般建议继承Exception,好处是必须要处理异常
来源:https://blog.csdn.net/m0_47988201/article/details/120246376


猜你喜欢
- 本文实例为大家分享了WPF自定义选择年月控件的具体代码,供大家参考,具体内容如下封装了一个选择年月的控件,XAML代码:<UserCo
- @ConfigurationProperties注入创建一个新的模板此过程就不在这介绍了,在我SpringBoot专栏里有详细过程。⭐⭐⭐注
- 汉诺塔问题是学习递归的入门问题,这里用C#简单实现了一个汉诺塔之间传递盘子的小程序通过简单绘图实现盘子在几个塔之间的转换:namespace
- 什么是数组数组是相同类型数据的有序集合数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个数组元素,每
- Java IO BufferedInputStream概要:BufferedInputStream是缓冲输入流,继承于Filte
- <profiles> <profile> <
- 十进制转二进制正整数转二进制除2取余,逆序排列,高位补零。示例:十进制255 = 二进制1111 1111计算过程:255/2=127===
- 前言:List 去重指的是将 List 中的重复元素删除掉的过程。此题目考察的是对 List 迭代器、Set 集合和 JDK 8 中新特性的
- 一、dfs(深度优先搜索)1.图的dfs/** * 深度优先搜索 * * @param node * @param set */publi
- 前言此节假日为严格按照国家要求的双休和法定节假日并且包含节假日的补班信息,大家可根据自己的需求自定义处理哦。以下为Maven配置,是程序用到
- Service层:public int addUser(UserDomian user){ int i = userMapper
- Java IO 转化流乱码引起转换流读取乱码读取电脑磁盘上的Java.txt文件内容,文件路径: e:\Java\Java.txt
- Android中的消息处理机制大量依赖于Handler。每个Handler都有对应的Looper,用于不断地从对应的MessageQueue
- 在工作中,如果需要跟XML打交道,难免会遇到需要把一个类型集合转换成XML格式的情况。之前的方法比较笨拙,需要给不同的类型,各自写一个转换的
- 前言本文提供三种不同的解决方式,也是三种不同的情况和思路我的问题是在springboot整合了xxl-job一段时间后出现的。如果你程序里集
- 在使用EL时,其实EL是先看标识符是否是其隐式对象之一,如果不是,才从四个域(page、request、session、applicatio
- 需求业务需要导出的Excel的数字内容保留两位小数,并且四舍五入代码实现百度一圈所抄袭的代码DecimalFormat dfScale2 =
- 背景:最近项目中涉及到自定义线程池中子线程获取父线程的traceId,这个数据的传递过程可以用lamdba表达式进行封装实现的。这让我想到s
- 目录@ConfigurationProperties使用@ConfigurationProperties特点宽松绑定支持复杂属性类型激活@C
- 智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delet