引言
本篇博文为 Java 异常处理的常见概念及相关细节梳理,意在重学 Java 查漏补缺。
博文随时会进行更新,补充新的内容并修正错漏,该系列博文旨在帮助自己巩固扎实 Java 基础。
毕竟万丈高楼,基础为重,借此督促自己时常温习回顾。
异常概述
异常:在 Java 语言中,将程序执行中发生的不正常情况称为 “异常”。(开发过程中的语法错误和逻辑错误不是异常)
Java 程序在执行过程中所发生的异常事件可分为两类:
- Error:Java 虚拟机无法解决的严重问题。
- 如:JVM 系统内部错误、资源耗尽等严重情况。
- 比如:StackOverflowError(栈溢出) 和 OOM(OutOfMemoryError 堆溢出)
- 一般不编写针对性的代码进行处理
- Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理,例如:
- 空指针访问
- 试图读取不存在的文件
- 网络连接中断
- 数组下标(索引)越界
对于这些错误,一般有两种解决方法:
- 遇到错误就终止程序的运行
- 在编写程序时,考虑到错误的检测、错误消息的提示以及错误的处理
异常分类
捕获错误最理想的是在编译期间,但有些错误只有在运行时才会发生,比如:
- 除数为零(一个数除以 0)
- 数组下标越界
分类为:编译时异常、运行时异常
编译时异常(受检异常 checked)
- Throwable
- Exception
- IOException
- EOFException
- FileNotFoundException
- MalformedURLException
- UnknownHostException
- ClassNotFoundException
- CloneNotSupportedException
- IOException
- Exception
运行时异常(非受检异常 unchecked)
Error
- RuntiomException
- ArithmeticException
- ClassCastException
- IllegalArgumentException
- IllegalStateException
- IndexOutOfBoundsException
- NoSuchElementException
- NullPointerException
常见异常
java.lang.Throwable |
异常处理
异常的处理:“抓抛模型”
- “抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出。
一旦抛出对象后,其后的代码就不再继续执行 - “抓”:可以理解为异常的处理方式
- try-catch-finally
- throws
Java 程序的执行过程中如出现异常,会生成一个异常类对象,该异常类对象将被交给 Java 运行时系统,这个过程称为抛出(throw)异常
异常对象的生成:
- 由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出 —— 自动抛出
- 由开发人员手动创建:Exception exception = new ClassCastException(); —— 创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样
try-catch-finally
格式:
try { |
说明:
- finally 是可选的
- 使用 try 将可能出现异常的代码包装起来,在执行过程中,一旦出现异常,就会生成一个异常类的对象,根据此对象的类型,去 catch 中进行匹配
- 一旦 try 中的异常对象匹配到某一个 catch 时,就进入 catch 中进行异常的处理。一旦处理完成就跳出当前的 try-catch 结构(在没有 finally 的情况)。继续执行其后的代码
- catch 中的异常类型如果没有子、父类关系,则声明顺序随意
catch 中的异常类型如果满足子、父类关系,则要求子类一定声明在父类之前,否则编译报错 - 常用的异常对象处理的方式:
- String getMessage():打印异常信息
- printStackTrace():打印堆栈
- 在 try 结构中声明的变量,在出了 try 结构后不能再被调用
- try-catch-finally 结构可以嵌套
注意:使用 try-catch-finally 处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。相当于使用 try-catch-finally 将一个编译时可能出现的异常延迟到运行时出现
throws + 异常类型
- “throws + 异常类型” 写在方法的声明处。指明此方法执行时,可能会抛出的异常类型
一旦方法执行时出现异常,仍会在异常代码处生成一个异常类对象,此对象满足 throws 后的异常类型时,就会被抛出。异常代码后续的代码不再继续执行 - try-catch-finally 方式真正的将异常进行了处理
throws 方式只是将异常抛给了方法的调用者,并没有真正将异常进行处理
try-catch-finally 与 throws 的使用场景
开发中根据不同场景选用不同的处理方式
- 如果父类中被重写的方法没有 throws 方式处理异常,则子类重写的方法也不能使用 throws,意味着如果子类重写的方法中若涉及异常,必须使用 try-catch-finally 方式处理
- 要执行的方法中,先后又调用了另外的几个方法,这几个方法是通过递进关系执行的,这时建议这几个方法使用 throws 方式进行处理;而这个要执行的方法可以考虑使用 try-catch-finally 方式进行处理
手动抛出异常
格式:throw new 异常类构造器(参数);
throw 和 throws 的区别:
- throw 表示抛出一个异常类的对象,生成异常类的过程。声明在方法体内
- throws 属于异常处理的一种方式,声明在方法的声明处
自定义异常类
自定义异常的方式:
- 继承于现有的异常类:RuntimeException、Exception
- 提供全局常量:serialVersionUID:(唯一标识)
- 提供重载的构造器