前言
越是简单,越容易忽略。编码一切应该从简单开始,简单点,编码的方式简单点,正确点,对待异常的方式正确点。
一, JAVA异常类结构
Java异常类结构: Java异常类结构如下图。基类为Throwable,Error和Exception继承Throwable,RuntimeException和IOException等继承Exception,NullPointerException继承RuntimeException,可以说,在Java中,除了Error之外,所有的异常类都直接或间接地继承自Exception。
Java异常分类:
① ,非运行时/编译时异常。在Java中,凡是继承自Exception但不是继承自RuntimeException的类都是非运行时异常,又称为编译时异常。
② ,运行时异常。Error和所有直接或间接地继承自RuntimeException的异常都是运行时异常,常见的有NullPointerException,IllegalArgumentException,IndexOutOfBoundsException等
Exception | 含义 |
---|---|
NullPointerException | 指针 |
IllegalArgumentException | 非法参数 |
IllegalStateException | 非法状态 |
IndexOutOfBoundsException | 索引出界 |
UnsupportedOperationException | 不支持的操作 |
SQLException | 操作数据库异常 |
ClassCastException | 数据类型转换异常 |
NumberFormatException | 字符串转换数字异常 |
ArithmeticException | 除数为0的异常 |
BufferOverflowException | 缓冲区上溢异常 |
BufferUnderflowException | 缓冲区下溢异常 |
EmptyStackException | 空栈异常 |
二, Android异常分类
1, Java异常
在Java中出现未捕获异常,导致程序异常终止退出。即上面说到的Java Exception中的RuntimeException。
2, ANR(Application Not Responding)
应用与用户进行交互时,在一定时间(如主线程输入事件中为5秒)内没有响应用户的操作,则会引发ANR错误,并弹出一个系统提示框,让用户选择继续等待或立即关闭程序。同时会在/data/anr目录下生成一个traces.txt文件,记录系统产生ANR异常的堆栈和线程信息。
3, Native异常
Native异常/崩溃指在Native代码(C/C++)中,因访问非法地址,地址对齐等问题,或程序主动abort所产生相应的Signal导致程序异常退出。Linux中定义了很多Signal,当然并不是所有的Signal都会引发崩溃,一般会引发异常退出的Signal有SIGSEGV,SIGABRT,SIGILL,SIGBUS,SIGFPE等。Native异常具有与Java异常不同的特点:
- 程序会直接闪退到系统桌面。
- 出错时不会弹出提示框提醒程序崩溃(Android5.0以下) 。
三, Android异常处理方法
1, 编译时异常
在编译阶段被处理的异常,编译器会强制程序处理所有的编译时异常,也就是用try…catch显式地捕获并处理。Java认为这类异常都是可以被处理/修复的,同时在Java API文档的方法说明中,都会添加是否throw某个exception,这个exception就是编译时异常。
2, 运行时异常
在运行时没有相应的try…catch处理该异常对象,所以Java运行环境将会终止,程序将推出。针对这类异常处理方法:
- 认为加try…catch。这是一种非常low,非常不可取的方法,因为如果所有代码都加try…catch,那么对代码真正问题所在,无法处理和解决该问题。当然这样做并不是不可取。
- 个性化退出。我们可以在程序退出前,弹出一个个性化的对话框或者重启应用来代替Android系统默认强制退出应用程序。实现方式可以查阅资料,这里不做过多介绍。另外对于一些异常我们是可以做拦截操作的,比如空指针这类问题,如果出现了不让程序崩溃,但是这些方式本人建议尽量不要去做。因为程序中的异常本身可以看成是帮助我们查找问题,和提升程序的稳定性的,去掉或者中和掉得不偿失。
四, 正确使用try…catch
- 需要异常捕获的地方,比如:类型转换等。不要随意去添加异常,分析代码稳定性。
- 如果有多个Exception,不要利用Exception捕获所有潜在的异常。
- 如果try语句块中存在return语句,那么首先会执行finally语句块中的代码,然后才返回。
- 如果try语句块中存在System.exit(0)语句,那么不会执行finally语句块的代码,因为System.exit(0)会终止当前运行的JVM,程序JVM终止前结束执行。
- 当使用多个catch语句块来捕获异常时,需要将父类的catch语句块放到子类型的catch块之后,这样才能保证后续的catch可能被执行,否则子类型的catch将永远无法到达,Java编译器会报编译错误。
- 不要将异常包含在for循环语句中,因为异常处理是占用资源的。