本帖最后由 小石姐姐 于 2017-12-11 16:04 编辑
异常概述和体系
* 异常
* 不正常的情况,是代码在编译或者运行时发生的错误
* 常见异常
* NullpointerException
* ArrayIndexOutOfBoundException
* java.lang.Throwable(最顶层)
|_ Error (不应该试图捕获的严重问题, 不能处理的异常)
|_ Exception (可以处理的异常) # 编译时异常: 编译时期就会发生的异常
|_ RuntimeException # 运行时异常: 编译时正常, 运行时才会发生的异常
* 异常输出信息详解
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at com.itheima.practice_08.MapTest.main(MapTest.java:31)
解释:
* Exception in thread "main": 在名为"main"的线程发生异常
* java.util.ConcurrentModificationException: 异常的具体类型, 这里是并发修改异常
* at xxx.xxx.xxx: 异常发生的位置, 因为层层方法调用, 所以会出现多个类的方法, 这些方法组成了异常链
* 只要不是我们的包名, 一般不用看. 是我们的包名, 才看
* at com.itheima.practice_08.MapTest.main(MapTest.java:31): 说明这个异常, 发生在我们的com.itheima.practice_08下的MapTest类的main方法中, 具体是MapTest.java文件中的第31行
* 一般MapTest.java:31这一部分是可以鼠标点击的, 点击后就直接跳转到报错的这一行
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.itheima.practice_01.ExceptionTest.main(ExceptionTest.java:9)
解释:
* / by zero: 是异常的说明信息, 有的异常有说明信息, 有的没有
* 其他和上例一样
### jVM默认的异常处理方式,以及try...catch方式
* 异常的处理方式
* JVM默认处理方式
* 如果开发者没有处理异常,则JVM会把异常的类型原因位置显示在控制台,并终止程序,发生异常之后的代码不会执行
* 手动处理
* 捕获异常并处理try...catch
* 提前对可能发生的异常进行处理,纠正错误避免程序终止
* 但代码在发生异常后,某些值可能无法预测,继续运行可能发生潜在的问题
* 使用`try...catch...`处理异常的代码格式:
// 捕获异常
try {
// 将可能会发生异常的代码
// 放在这里
// 可以有多行代码
} catch (异常类型 异常对象名) {
// 对异常进行处理的代码
// 也可以通过异常对象名获取异常的信息
}
* `try...catch`的执行顺序:
* 先执行try代码块中的代码
* 如果没有发生异常, 则不执行catch代码块的代码, 继续执行catch代码块之后的代码
* 如果发生了异常, 则从try代码块中发生异常的那一行代码**直接进入**catch代码块中执行, 然后继续执行catch代码块之后的代码
* 直接进入就是说, try代码块中发生异常那一行代码之后的代码不会执行
* 注意:
* catch可以捕获到该异常类型及其子类的异常, 这是多态
* catch括号中应该填什么异常呢?
* 如果知道具体会抛出的异常类型, 则写该异常类型, 如`NullPointerException`
* 如果不知道会抛出什么异常, 则可以写异常的较高类, 一般写`Exception`类(利用多态)
* 捕获和抛出的异常类型怎么知道?
1. 如果是编译时异常, IDE会提示, 直接使用
2. 如果是运行时异常, 只能运行一次该代码, 看到异常信息的类型后, 手动复制过来. 以后记住了再直接写
3. 直接使用Exception类型, 它包含了所有异常的子类(多态)
* 直接抛出异常,在方法声明上throws
* 不捕获异常,当发生异常想方法外界抛出,知道最顶层的方法终止程序
* 一般无法处理异常,或希望外界处理异常时使用
* 手动抛出异常
* 使用`throws`关键字(记住这个带s)
* throws就是抛出的意思
* 作用: 不捕获异常, 当发生异常时向方法外界抛出, 直到最顶层的方法, 最终终止程序
* 使用场景: 一般在该方法不能处理异常, 或希望外界处理异常时使用
* 定义位置: 方法形参后, 如果抛出多个异常, 可以用`,`逗号分隔
* 注意:
* 定义在方法上的抛出异常属于编译时异常, 编写代码调用该方法时IDE会提示去处理异常
* 抛出异常的定义格式
// 定义格式
方法名(参数列表) throws 异常类型1, 异常类型2... {
}
多异常处理
* 多异常的捕获:
* 可以写多个catch代码块来分别处理同一个try代码块中的多个异常
* 多异常捕获中catch的顺序
* 如果没有继承关系, 则catch的顺序可以随意定义
* 如果异常是继承关系的类, 必须子类在上, 父类在下
* 原因: 因为父类包含子类的异常, 如果上方被父类异常的catch捕获了, 那么捕获子类异常的catch永远也不会用到
* 多个catch代码块的执行逻辑
* try代码块中抛出的异常, 如果catch中有对应的具体异常, 则执行对应的catch代码块. 其他catch代码块不会执行(类似于if...else if, switch...case)
* try代码块中抛出的异常, 如果catch中没有对应的具体异常, 则所有catch代码块都不会执行. 相当于异常没有捕获, 仍然会导致程序终止
try {
// 可能发生异常的代码
} catch (异常类型1 异常对象名1) {
// 处理异常1的代码
} catch (异常类型2 异常对象名2) {
// 处理异常2的代码
}
* 补充: JDK1.7新特性: 在一个catch中捕获多个异常类型
* 在一个catch的参数中填写多个异常类型, 格式: `catch (异常类型1 | 异常类型2 异常变量名) {}`
* 注意
* 不同异常类型之间用`|`分隔, 变量名只有一个
* catch代码块中, 由于不同异常类型都只对应同一个变量名, 所以在需要判断是哪种异常时, 可以使用`变量名 instanceof 异常类型`来判断具体是何种类型; 如果不需要针对具体异常类型分别处理, 可以不判断异常类型, 统一通过异常变量名来做统一的处理, 示例如下:
// 格式
try {
// 可能抛出异常的代码
} catch (异常类型1 | 异常类型2 异常变量名) {
// 异常处理代码
if (异常变量名 instanceof 异常类型1) {
// 处理异常类型1
} else if (异常变量名 instanceof 异常类型2) {
// 处理异常类型2
}
}
|
|