文章目录

  • Error
  • Exception
  • 抛出异常
  • throw
  • throws
  • 捕获异常
  • Android全局异常的捕获
  • 预防异常



异常是指程序指令非正常执行的情况,比如空指针、数组下标越界、类型强制转换异常等,由此导致程序异常退出。Java里面的分两类:一个Error,一个Exception,它们都继承自Throwable。见图所示:


Android 不退出 异常捕获 android异常处理机制_抛出异常

Error

Error情况是程序本身不能处理的,比如JVM自身的异常,导致程序处于非正常不可恢复状态,比如常见的OutOfMemoryError内存溢出异常。

Exception

程序中能够处理的就是Exception了。
Exception也分两类,一个是运行时异常,一个是非运行时异常

运行时异常就是程序运行时产生的异常,也是我们平常最常见到的异常。像NullPointerException、IndexOutOfBoundsException等。
对于运行时异常,java编译器不要求强制进行异常处理或声明,由程序员自行决定;

非运行时异常,顾名思义就是在程序运行前的异常,也就是编译异常,Java编译器会要求我们强制进行异常处理,比如FileNotFoundException、IOExeption、SQLException、JSONException之类的异常。
比如读文件的方法,可能存在文件不存在的情况,那么Java编译器会要求我们强制捕获并处理FileNotFoundException这类的异常。

抛出异常

throw

  1. 只能用在方法体内;
  2. 抛出的是一个异常实例对象;
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

  1. 跟在方法名后面;
  2. 可以跟多个异常类名;
  3. 由该方法调用者处理该抛出的异常;

例子见上面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异常为例:

  1. 增加字符串判空:if(StringUtils.isEmpty(str)){ …}
  2. equal判断:(“常量”).equals(var); 常量在equals前面;
  3. toString:String.valueOf(…),而不是var.toString();
  4. 使用@NonNull 和 @Nullable注解,借助编译器帮助编译前排查null对象;
  5. 使用Guava的checkNotNull,帮助我们主动抛出异常;