异常
所谓 异常 指的就是程序在 运行时 出现错误时通知调用者的一种机制。
注意,运行时,是指已经编译成为class文件,在JVM运行过程中。
在编程时,代码出现问题是很常见的,我们有两种处理方式:
LBYL: Look Before You Leap. 在操作之前就做充分的检查.
EAFP: It’s Easier to Ask Forgiveness than Permission. “事后获取原谅比事前获取许可更容易”. 也就是先操作, 遇到 问题再处理.
对于我们的Java来说,显而易见是EAFP式编程。
常用的语句:
```java
try{
有可能出现异常的语句 ;
} catch (异常类型 异常对象) {
语句
} finally {
异常的出口
}
try:代码块中放的是可能出现异常的代码.
catch:代码块中放的是出现异常后的处理行为.
finally:代码块中的代码用于处理善后工作, 会在最后执行.
其中 catch 和 finally 都可以根据情况选择加或者不加.显而易见,这个代码就是数组访问越界异常,这是由JVM处理的,但当JVM处理结束后,那么后续代码就不会继续执行了,当然我们也可以手动处理异常:
可以看到的是,我们手动处理的异常,及时出现问题但仍然会执行后续语句。
对于异常的处理,我们要知道:
1.对于比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果;
2.对于不太严重的问题(大多数场景), 可以记录错误日志, 并通过监控报警程序及时通知程序猿
3.对于可能会恢复的问题(和网络相关的场景), 可以尝试进行重试.
3.在我们当前的代码中采取的是经过简化的第二种方式. 我们记录的错误日志是出现异常的方法调用信息, 能很快 速的让我们找到出现异常的位置. 以后在实际工作中我们会采取更完备的方式来记录异常信息
除此之外,要知道catch只能抓到你所标记的包,如果你在catch中写的是空指针异常,那么你就处理不到,会被JVM所处理。(如下图)
当然我们可以多次catch。具体就不演示了。我们这有一种可以抓住绝大部分的异常(但是不推荐):
之所以可以这样是因为,Exception是所有异常的父类
异常处理流程
1.程序先执行 try 中的代码
2.如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.
3.如果找到匹配的异常类型, 就会执行 catch 中的代码
4.如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
5.无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
6.如果上层调用者也没有处理的了异常, 就继续向上传递.
7. 一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.
当在方法找不到异常处理时,那么就会往上层调用者找,如果找不到JVM就会处理。(图示两个位置try catch都可以)
处理被动的抓异常外,我们也可以手动抛出异常(关键字:throw):
这里注意,一旦抛出异常,后续代码不会执行的。
这里还有一个关键字,是用来提醒程序员可能抛出异常的:
上图是Java的继承体系。
1.顶层类 Throwable 派生出两个重要的子类, Error 和 Exception
2.其中 Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现, 除了告知用户并使程序终止之外, 再无能无力. 这种情况很少出现. 3.Exception 是我们程序猿所使用的异常类的父类.
4.其中 Exception 有一个子类称为 RuntimeException , 这里面又派生出很多我们常见的异常类 NullPointerException , IndexOutOfBoundsException 等.
其实本质上来说,异常就是特殊的类,那么我们其实也可以创建这种类,即,用户自定义的异常:
class UserError extends Exception {
public UserError(String message) {
super(message);
}
}
class PasswordError extends Exception {
public PasswordError(String message) {
super(message);
}
}
就是这样的用途。
注意:
1.自定义异常通常会继承自 Exception 或RuntimeException
2.继承自 Exception 的异常默认是受查异常
3.继承自 RuntimeException 的异常默认是非受查异常.
Java语言规范将派生于 Error 类或 RuntimeException 类的所有异常称为 非受查异常, 所有的其他异常称为 受查异常.
如果一段代码可能抛出 受查异常, 那么必须显式进行处理.