一、异常体系结构
- Throwable 类是 Java 语言中所有错误或异常的超类。
- 只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。
- Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。
最后,它还可以包含 cause(原因):另一个导致此 throwable 抛出的 throwable。此 cause 设施在 1.4 版本中首次出现。它也称为异常链 设施,因为 cause 自身也会有 cause,依此类推,就形成了异常链,每个异常都是由另一个异常引起的。
1、Error
Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。
- 大多数这样的错误都是异常条件。虽然 ThreadDeath 错误是一个“正规”的条件,但它也是 Error 的子类,因为大多数应用程序都不应该试图捕获它。
- 在执行该方法期间,无需在其 throws 子句中声明可能抛出但是未能捕获的 Error 的任何子类,因为这些错误可能是再也不会发生的异常条件。
- Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
2、Exception
- Exception 异常主要分为两类
- 一类是 IOException(I/O 输入输出异常),其中 IOException 及其子类异常又被称作「受查异常」
- 另一类是 RuntimeException(运行时异常),RuntimeException 被称作「非受查异常」。
受查异常就是指,编译器在编译期间要求必须得到处理的那些异常,你必须在编译期处理了。
2.1 常见的受检性异常
2.2 常见的非受检性异常
二、自定义异常
Java 的异常机制中所定义的所有异常不可能预见所有可能出现的错误,某些特定的情境下,则需要我们自定义异常类型来向上报告某些错误信息。
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
如果一个方法没有捕获一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
- 下面方法的声明抛出一个 RemoteException 异常:
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。public class className {
public void deposit(double amount) throws RemoteException {
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
四、其他
1、OutOfMemoryError 可以被 try catch 吗?
OutOfMemoryError 是可以 try catch 的。
RuntimeException 是在程序运行中可能发生的异常,我们可以不捕获它,但可能带来 Crash 的代价,但是过多的捕获异常又不利于暴露和调试异常情况。在开发过程中,我们更多的应该及时暴露问题。除了 RuntimeException 以外,其他异常可以统称为 非运行时异常 或者 受检异常,这些异常必须被捕获,否则编译期就会报错。
OutOfMemoryError 的父类们
OutOfMemoryError 是一个 Error ,Error 不应该被捕获。那么,捕获 OutOfMemoryError 有什么意义呢?OutOfMemoryError <- VirtualMachineError <- Error
如果你把捕获 OOM 当做处理 OOM 的一种手段,无疑是不合适的。你无法保证你 catch 的代码就是导致 OOM 的原因,可能它只是压死骆驼的最后一根稻草,甚至你也无法保证你的 catch 代码块中不会再次触发 OOM 。
在 View.java 的 buildDrawingCacheImpl() 方法中有这么一段代码:
buildDrawingCacheImpl() 方法的大致作用是为当前 View 生成一个 Bitmap 缓存。在构建 Bitmap 对象的时候,如果捕捉到了 OOM ,就放弃生成 Bitmap 缓存,因为在 View 的绘制过程中 Bitmap Cache 并不是必须存在的。try {
bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
width, height, quality);
bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
if (autoScale) {
mDrawingCache = bitmap;
} else {
mUnscaledDrawingCache = bitmap;
}
if (opaque && use32BitCache) bitmap.setHasAlpha(false);
} catch (OutOfMemoryError e) {
// If there is not enough memory to create the bitmap cache, just
// ignore the issue as bitmap caches are not required to draw the
// view hierarchy
if (autoScale) {
mDrawingCache = null;
} else {
mUnscaledDrawingCache = null;
}
mCachingFailed = true;
......
所以在这里没有必要抛出 OOM ,而是自己捕获就可以了。
在你自己明确知道可能发生 OOM 的情况下设置一个兜底策略,这可能是捕获 OOM 的唯一意义了。
JVM 中哪一块内存不会发生 OOM ?
Java内存区域——堆,栈,方法区等
唯一一个在《Java虚拟机规范》中没有规定任何 OutOfMemoryError 情况的区域是 程序计数器。程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地(Native)方法,这个计数器值则应为空(Undefined)。