Java入门7---异常处理
一、Java中异常的分类
当执行一个程序时,如果发现异常,则异常之后的代码就不再执行。Throwable 类是 Java 语言中所有错误或异常的超类,其子类有Exception和Error。JDK文档有这么一句话:只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。也就说Error也是catch子句的参数类型,不只是Exception。由于Error是错误,正常的程序时不应该捕获的,因为这些错误消除后可能再也不会出现,所以我们几乎从来没有看到catch子句中捕获Error的情况,但是Error还是可以被捕获。
1.Error
Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。一般不编写针对性的代码进行处理。
2.Exception
其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
- 空指针访问
- 试图读取不存在的文件
- 网络连接中断
2.1 编译时异常
在编译期间会出现的异常(执行javac.exe命令时,出现异常)
2.2 运行时异常
在运行期间出现的异常(执行java.exe命令时,出现异常)
出现运行时异常后,系统会把异常一直往上层抛出,直到遇到处理代码为止。若没有处理块,则抛到最上层;如果是多线程就用Thread.run()方法抛出,如果是单线程,就用main()方法抛出。抛出之后,如果是线程,那么这个线程也就退出了。如果是主程序抛出的异常,那么整个程序也就退出了。所以,如果不对异常进行处理,后果是非常严重的,一旦发生,要么是线程中止,要么是主程序终止。
二、异常处理
- 对于运行时异常,可以不显示的进行处理
- 对于编译时异常,必须要显示的进行处理
1.如何处理Exception异常
- 上游:手动抛/自动抛
- 下游:try-catch-finally/throws
上下游各有两种方法,可以自由搭配。
抓抛模型:
- “抓”:抓住上一步抛出来的异常类的对象。如何抓?即为异常处理的方式。
- “抛”:一旦抛出此异常类的对象,那么程序就终止执行,此异常类的对象抛给方法的调用者。
1.1 抓
1. try-catch-finally
1 2 3 4 5 6 7 8 9 | try { // 可能出现异常的代码 } catch (Exception e1){ // 处理的方式1 } catch (Exception e2){ // 处理的方式2 } finally { // 一定要执行的代码 } |
注意:
- try内声明的变量,类似于局部变量,出了try{}语句,就不能被调用
- finally是可选的
- catch语句内部是对异常对象的处理
- 可以有多个catch语句,try中抛出的异常类对象从上往下去匹配catch中的异常类的类型,一旦满足就执行catch的代码。执行完,就跳出其后的多条catch语句。
- 如果异常处理了,那么其后的代码继续执行。
- 如果catch中多个异常类型是“并列”关系,谁上谁下都可以;如果catch中多个异常类型是“包含”关系,须将子类放在父类的上面,进行处理,否则报错!
- finally中存放的是一定会被执行的代码,不管try中、catch中是否仍有异常未被处理,以及是否有return语句。
- try-catch是可以嵌套的。
finally块中的return情况分析:
try语句在返回前,将其他所有的操作执行完,保留好要返回的值,而后转入执行finally中 的语句,而后分为以下三种情况:
情况一:如果finally中有return语句,则会将try中的return语句”覆盖“掉,直接执行finally 中的return语句,得到返回值,这样便无法得到try之前保留好的返回值。
情况二:如果finally中没有return语句,也没有改变要返回值,则执行完finally中的语句 后,会接着执行try中的return语句,返回之前保留的值。
情况三:如果finally中没有return语句,但是改变了要返回的值,分以下两种情况,
总体说明:将要返回变量重新赋予一个new的对象,返回还是之前的。
1)如果return的数据是基本数据类型或文本字符串,则在finally中对该基本数据的改变不 起作用,try中的return语句依然会返回进入finally块之前保留的值。
2)如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起 作用,try中的return语句返回的就是在finally中改变后的该属性的值
举例1:
没有异常 | 有异常 |
![]() |
有finally时,先执行finally里面语句,再报异常。 |
举例2:面试题
2. 在方法的声明处显示的抛出该异常对象的类型 throws
如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
如:
1 2 3 4 5 6 | public void readFile(String File) thorws FileNotFoundException { ... // 读文件的操作可能产生FileNotFoundException类型的异常 FileInputStream fis = new FileInputStream(file); ...... } |
当在此方法内部出现异常的时候,会抛出一个异常类的对象,抛给方法的调用者。
异常的对象可以逐层向上抛,直至main中。当然在向上抛的过程中,可以再通过try...catch...finally进行处理。
1.2 抛
1. 自动抛出 |
2. 手动抛出 |
|
|
抛异常,不处理(throw是回避问题的方式) |
|
抛异常,处理(try-catch是真正解决问题的方式) |
手动抛出的异常类对象(throw new Exception("异常")),既可以是现成的异常类,也可以是自己创建的异常类。
|
3. 自定义异常类
方法:
- 继承现有的异常类;
- 提供一个序列号,提供几个重载的构造器。
举例1:
举例2:
举例3:
![]() |
||
|
4. 抛异常的方法的重写规则
子类重写父类的方法,其抛出的异常类型只能是被重写的方法的异常类的子类或异常类型一样。
因为如果子类抛出的异常比父类的还大,则在编译的时候不会报错,因为编译时候默认还是会catch父类抛出的异常,但是在方法的执行过程中,还是会执行子类的异常,如果抛出的异常大,catch方法会失效,说明程序的设计是有一定问题的。
三、try-with-resources
使用try-with-resources优雅的关闭资源。try-with-resources语句保证了每个声明了的资源在语句结束的时候都会被关闭。
任何实现了java.lang.AutoCloseable接口的对象,或者实现了java.io.Closeable接口的对象,都可以当做资源使用,Closeable继承了AutoCloseable,任何的catch和finally代码块都在所有被声明的资源被关闭后执行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
2019-08-06 基变换