学习异常处理完整篇
/**
* 异常处理
一 分类
Throwable
Error(不要处理Error错误)
AWTError IOError LinkageError ThreadDeath
Exception(分为两大类check和RuntimeException异常,它们都可以显式处理和throws声明处理)
checked不是运行时异常的异常就是check异常,注意没有这个类,所以我故意首字母小写
IOException SQLException ...
RuntimeException(RuntimeException及其子类都是Runtime异常)
IndexOutOfBoundsException NullPointException ClassCastException .....
二 异常捕获的写法(try-catch-finally)
(I) 简单写法 try{} catch(){}
(II) 完整写法 try(){} catch(Exception e){//一个或多个catch代码块}....finally{}
1 try代码块必要,大括号不可以省略
2 catch代码块可以包含多个,但是异常对象捕捉,必须先小后大
3 finally代码块 可有可无,看需要添加
4 ()小括号 看需要添加,用于关闭物理资源
注意:try代码块必要,而catch块和finally二选一或同时出现,try-catch-finally,不可以割裂看待和使用,要作为一体来看待
三 多异常捕捉(java7开始一个catch块可以捕捉多种类型的异常)
1 多个异常用'|'竖线隔开
2 捕捉多种类型的异常,异常变量有隐式的final修饰,因此不可以对异常变量重新赋值.
3 多种类型的异常之间不可存在父子关系
正常 catch(ClassCastException | IndexOutOfBoundsException |NumberFormatException e ){}
报错 catch(Exception | ClassCastException | IndexOutOfBoundsException |NumberFormatException e ){}
四 访问异常信息(只能在catch块中通过异常对象来访问异常信息)
所有的异常对象都给包含了如下方法
String getMessage() 返回该异常对象的详细描述信息
void printStackTrace() 将该异常的跟踪栈信息输出到标准错误输出
void printStackTrace(PrintStream ps) 将该异常的跟踪栈信息输出指定输出
StackTraceElement[] getStackTrace() 返回该异常的跟踪栈
五 finally代码块
起因: 垃圾回收机制不会回收任何物理资源,只会回收堆内存中的对象所占的内存
注意:
1 正常情况下finally语句永远可以得到执行,即使try块或catch块执行return或throw等方法退出的语句,现在知道为什么它叫finally了吧
(System.exit(1)执行导致退出虚拟机除外,当然没人这么干,还是记住那句话,正常情况下finally语句永远可以得到执行)
2 不要在finally块中使用return或throw等导致方法退出的语句.(因为这将导致try块或catch块的return,throw语句失效.)
3 finally无法修改try或catch块中return返回的值和throw语句的内容,即使修改的return或throw语句中中变量的值也如此
因为return返回的值已经被执行了,产生了一个结果x,此时才执行finally语句,最后返回x结果.
(执行finally语句前return语句的返回值结果已经产生.throw抛出异常语句也是如此)
六 java9增强的自动关闭资源的try语句块(java7事实上已经有了自动关闭try语句块)
写法: try(){}-catch-finally
要求:
1 要么在小括号里声明且初始化(java7)注意'且'字
2 (推荐)要么在try自动关闭语句之前初始化,然后再try的小括号的声明一下即可,多个资源需要分号间隔(java9增强)
java9解释: 资源变量必须为final的. 要么必须要么final显式声明类型,要么是隐式final修饰(小括号里声明即成了被隐式final修饰)
3 可以包含catch语句或finally语句.(二选一或同时出现)
注意:
1 为保证正常关闭,这些资源类必须实现AutoCloseable或Closeable接口,事实上java的这些资源类已经实现了)
2 自动关闭try语句块,其实相当于包含了隐式的finally语句块,所以它可以没有catch和finally,亦可以包含
七 check异常和Runtime异常
check异常处理(3种)
try-catch-finally,方法声明抛出(throws),throw手动抛出
Runtime异常处理(3种)
try-catch-finally,throw手动抛出,不处理让方法的调用者处理
八 throws 方法签名上声明抛出异常
1 用法: public void test()throws ClassCastException,IndexOutOfBoundsException,NumberFormatException{}
2 方法重写时声明抛出异常的限制
遵循方法重写的要求"两同两小一大",声明抛出异常类型要<=重写的方法抛出的异常类型.(注意没有对抛出异常类型的数量作要求)
九 使用throw手动抛出异常
用法: throw new Exception("使用throw手动抛出异常");
注意:
1 java7开始 java编译器可以检查throw语句抛出的异常的类型,并提示提示警告出来
实际上是,java编译器检查出的是捕捉异常对象时的编译类型,而不是实际类型
解释: java编译器保存了异常对象a在捕捉时的编译类型A,如果throw手动抛出该对象时,则在编译时提示要处理该异常对象a,并显示出它的类型信息A
如果有人在异常对象被捕捉前将类型A转为B类型.则java编译器检查异常对象为捕捉类型B.
当然没人吃饱了饭这样干,去强转异常对象的类型.我们还是正常理解java编译器可以检查throw语句抛出的异常的类型就可以了.
十 自定义异常类型
1 继承: 自定义异常继承Exception基类即可,如果自定义Runtime异常,继承RuntimeException.
2 提供2个构造器 一个无参,一个带一个字符串的构造器,(字符串实参就是getMessage()返回的信息)
3 调用父类构造器, 在字符串参数的构造器里,调用super构造器将字符串参数传入super(message)
十一 catch和throw同时使用
catch捕捉异常,只是打印异常信息,并不处理异常,而通过throw处理异常.
(两者配合处理异常.既打印了异常信息,又处理了异常-另外又捕捉到的异常.)
十二 异常链
在定义一个异常类时,声明一个构造器,该构造器其结构如下
public Xxx(Throwable t){super(t);}//和string参数构造器几乎一样
在catch块中通过该异常类型的对象包装实际的异常对象抛出,通过catch块的链式结构从而形成异常的链式处理.
十三 注意:
1 作用域 try/catch/finally它们的代码块,其实也是一个作用域,可以定义局部内部类,匿名内部类,局部变量,所以它们的作用域也在这个代码块里.
2 程序不再执行抛出异常a位置后的那个域的代码块包括try/catch/finally,方法(异常a在try/catch/finally中,则作用域为它们,在方法中则作用域为方法)
3 最多只能执行一个 try代码块抛出异常后即使有多个catch代码块,如果异常被捕捉,最多只能执行一个,要么没有捕捉到异常继续向外抛出异常
(且异常对象捕捉,必须先小后大,如果把大的如Exception放在前面,后面小的异常catch块永远无法捕捉异常)
4 不要处理Error错误 Error错误通常和虚拟机相关,如系统崩溃,虚拟机错误,动态链接失败等.
因此catch代码块不应该捕捉Error对象.当然定义方法时声明的异常也无需抛出Error及其子类异常
5 异常处理可以嵌套:嵌套代码可以放在try,catch,finally都可以,嵌套深度最好不要大于2层
6 try-catch-finally,不可以割裂看待和使用,要作为一体来看待(要十分注意)
*/
//自定义异常类
class MyException extends RuntimeException{
public MyException(){}
public MyException(String message){super(message);}
}
public class 异常处理 {
public static void main(String[] args) {
try {
//声明内部类
class A{
{
System.out.println("我是局部内部类的实例代码块");
}
}
//创建内部类对象
var a1 = new A();
//创建匿名内部类对象
var a2 = new A(){
{ System.out.println("我是匿名内部类的实例代码块"); }
A a = a1;
};
throw new MyException(a2 + "");
} catch (MyException e) {
System.out.println("打印捕捉到的异常信息==>" + e.getMessage());
}
//如下访问异常处理代码块的局部变量a1和a2报错
// System.out.println(a1);
// System.out.println(a2);
}
}
运行结果如下:
我是局部内部类的实例代码块
我是局部内部类的实例代码块
我是匿名内部类的实例代码块
打印捕捉到的异常信息==>com.china.school.oop.异常处理$1@21bcffb5
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报