文章目录
- Error
- Exception
- 抛出异常
- throw
- throws
- 捕获异常
- Android全局异常的捕获
- 预防异常
异常是指程序指令非正常执行的情况,比如空指针、数组下标越界、类型强制转换异常等,由此导致程序异常退出。Java里面的分两类:一个Error,一个Exception,它们都继承自Throwable。见图所示:
Error
Error情况是程序本身不能处理的,比如JVM自身的异常,导致程序处于非正常不可恢复状态,比如常见的OutOfMemoryError内存溢出异常。
Exception
程序中能够处理的就是Exception了。
Exception也分两类,一个是运行时异常,一个是非运行时异常。
运行时异常就是程序运行时产生的异常,也是我们平常最常见到的异常。像NullPointerException、IndexOutOfBoundsException等。
对于运行时异常,java编译器不要求强制进行异常处理或声明,由程序员自行决定;
非运行时异常,顾名思义就是在程序运行前的异常,也就是编译异常,Java编译器会要求我们强制进行异常处理,比如FileNotFoundException、IOExeption、SQLException、JSONException之类的异常。
比如读文件的方法,可能存在文件不存在的情况,那么Java编译器会要求我们强制捕获并处理FileNotFoundException这类的异常。
抛出异常
throw
- 只能用在方法体内;
- 抛出的是一个异常实例对象;
private void throwsTest(int a, int b) throws Exception1, Exception3 {
try {
......
} catch (Exception1 e) {
throw e;
} catch (Exception2 e) {
System.out.println("出错了!");
}
if (a != b) {
throw new
} Exception3("自定义异常");
}
Exception1:方法内部捕获后再抛出,交由该方法的调用者处理;
Exception2:方法内部捕获后处理完成,不再向上抛出;
Exception3:方法内部自行抛出异常,交由该方法的调用者处理;
throws
- 跟在方法名后面;
- 可以跟多个异常类名;
- 由该方法调用者处理该抛出的异常;
例子见上面throw代码。
需要说明一点的是该方法调用者如何处理该抛出的异常:
private void main() {
try {
throwsTest();
} catch (Exception e) {
e.printStackTrace();
}
}
可以看到,throwsTest方法的调用者main方法需要捕获throwsTest方法可能抛出的异常。
捕获异常
try catch是最常用的异常捕获手段:
try{
return JSON.parseObject(json);
}
catch (Exception e){
LogUtil.e(TAG, "toObject: " + e.getMessage());
} finally {
......
}
有一个地方需要注意的是,try中如果有return语句,那么它和finally直接的关系是怎么样的呢?
我们通过一个例子看下:
System.out.println(test());
public static int test() {
int x = 1;
try {
x++;
return x;
} finally {
++x;
System.out.println(x);
}
输出结果是:3,2
也就是finally会先执行,但是try中的return会先将变量x的值保存起来,然后再执行finally中的语句,最后将保存的值返回。
Android全局异常的捕获
Android提供了UncaughtExceptionHandler接口,我们可以新建一个实现了该接口的类,然后通过setDefaultUncaughtExceptionHandler方法注册这个接口,这样就可以捕获异常了。
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private static CrashHandler INSTANCE = new CrashHandler();
public static CrashHandler getInstance() {
return INSTANCE;
}
public void init(Context context) {
mContext = context.getApplicationContext();
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器
Thread.setDefaultUncaughtExceptionHandler(this);// 设置该CrashHandler为程序的默认处理器
}
@Override
public void uncaughtException(Thread t, Throwable e) {
if (mDefaultHandler != null) {
if (Constant.EXCEPTION_MVP_VIEW_NOT_ATTACHED.equals(e.getMessage())) {// for MVP when presenter calls view but view has already destroyed
return;
}
mDefaultHandler.uncaughtException(t, e);// 退出程序
}
}
}
预防异常
以场景的null异常为例:
- 增加字符串判空:if(StringUtils.isEmpty(str)){ …}
- equal判断:(“常量”).equals(var); 常量在equals前面;
- toString:String.valueOf(…),而不是var.toString();
- 使用@NonNull 和 @Nullable注解,借助编译器帮助编译前排查null对象;
- 使用Guava的checkNotNull,帮助我们主动抛出异常;