异常简介
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。例如 int a = 10 / 0;
那么你是因为你用0做了除数,会抛出 java.lang.ArithmeticException 的异常,这个异常是能够被捕获并做相应处理的。但是对于程序发生 了 OOM 内存溢出错误来说,就没有必要去做捕获了,因为你无法保证你 catch 的代码就是导致 OOM 的原因,可能它只是压死骆驼的最后一根稻草,甚至你也无法保证你的 catch 代码块中不会再次触发 OOM 。
为了能够更好地处理程序中的异常,我们需要了解 Java 和 C++ 中的异常类型。
Java 异常
Java 异常一般分为以下三种:
-
Error 错误:代表JVM本身的错误,处理程序运行环境方面的异常,不能通过代码处理。比如
OutOfMemoryError
、AWTError
等。 -
检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。比如
IOException
、SQLException
等。 -
运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。比如,程序中除数为0引起的错误、数组下标越界错误、错误的强制类型转换错误、使用了空对象
NullPointerException
等,它们虽然是由程序本身引起的异常,但不是程序主动抛出的,而是在程序运行中产生的。
C++ 异常
C++ 中只存在运行时异常,整体的使用逻辑也和 Java 一致,使用 try、catch、throw 语法对异常进行捕获处理。但是业界对于 c++ 异常处理的使用存在很大的争议。Google 就在代码规范、以及编译时明确禁止使用异常,如果真的需要使用到异常处理,则需要开启使用异常的编译选项。但是 Google 这么做是因为有很重的历史包袱,他们在项目中已经有大量的非异常安全的代码,如果要将这些代码全部改成使用 try catch 异常处理,工作量无疑是巨大的。虽然 try catch 异常处理会影响一些性能,但它带来的好处我认为是更大的。不过这些都是题外话,不在本文的讨论范围之内。
异常处理
在 Java 代码中处理 Java 抛出的异常和 jni 中处理 c++ 抛出的异常比较简单,直接使用 try catch 就可以做到,不是本文讨论的重点。本文主要会介绍如果在 Java 中处理 jni 抛出的异常以及 JNI 中处理 Java 抛出的异常两种情况。
JNI 中处理 Java 异常
一般在 Java 代码中,如果我们觉得一段逻辑可能会引发异常,可以直接使用 try catch 对这段逻辑进行捕获,并处理可能出现的异常。那么在 JNI 中,我们在调用 Java 代码时,是使用类似反射的机制来调用相应方法的,如果该方法引发异常,我们能否通过 throws Exception 的方式,把这个异常抛到 Java 层进行处理呢?
Java 代码:
public static native void tryCatchJavaException() throws JNIException;
public static void throwExceptionTest() {
int a = 10 / 0;
}
public static void handlerExceptionFinish() {
Log.d(TAG</