###異常處理java
異常測試例子:程序員
public native void testException1();
public static void main(String[] args) {
JniTest test = new JniTest();
try {
test.testException();
System.out.println("程序沒法繼續執行1,這句話不會被打印\n");
} catch (Throwable t) {
System.out.println("捕獲到JNI拋出的異常(Throwable),這句話會被打印" + t.getMessage() + "\n");
}
System.out.println("程序繼續執行2,這句話會被打印\n");
}
複製代碼
C代碼以下:bash
//異常處理
JNIEXPORT void JNICALL Java_com_test_JniTest_testException1
(JNIEnv * env, jobject jobj){
jclass clz= (*env)->GetObjectClass(env, jobj);
//屬性名字不當心寫錯了,拿到的是空的jfieldID
jfieldID fid = (*env)->GetFieldID(env, clz, "key1", "Ljava/lang/String;");
//此處拋出的異常,Java能夠經過Throwable來捕獲
printf("C can run , this will print");
//這裏居然還能夠繼續執行
jstring key = (*env)->GetObjectField(env, jobj, fid);
//遇到這句話的時候,C程序Crash了
char* c_str = (*env)->GetStringUTFChars(env, key, NULL);
printf("C could not run , this will not print");
}
複製代碼
經過例子能夠知道,JNI層本身拋出的異常是Error類型,Java能夠經過Throwable或者Error來捕得到到,捕獲異常後Java代碼能夠繼續執行下去。函數
#####爲了確保Java、C/C++代碼能夠正常執行下去,須要:測試
在JNI層手動清空異常信息(ExceptionClear),保證代碼能夠運行。 補救措施保證C/C++代碼繼續運行。 例如:ui
//異常處理
JNIEXPORT void JNICALL Java_com_test_JniTest_testException1
(JNIEnv * env, jobject jobj){
jclass clz = (*env)->GetObjectClass(env, jobj);
//屬性名字不當心寫錯了,拿到的是空的jfieldID
jfieldID fid = (*env)->GetFieldID(env, clz, "key1", "Ljava/lang/String;");
jthrowable err = (*env)->ExceptionOccurred(env);
if (err != NULL){
//手動清空異常信息,保證Java代碼可以繼續執行
(*env)->ExceptionClear(env);
//提供補救措施,例如獲取另一個屬性
fid = (*env)->GetFieldID(env, clz, "key", "Ljava/lang/String;");
}
jstring key = (*env)->GetObjectField(env, jobj, fid);
char* c_str = (*env)->GetStringUTFChars(env, key, NULL);
}
複製代碼
測試代碼以下:this
public static void main(String[] args) {
JniTest test = new JniTest();
try {
test.testException();
System.out.println("程序沒有異常,這句話會被打印\n");
} catch (Exception e) {
System.out.println("沒有捕獲到JNI拋出的異常,這句話不會被打印" + e.getMessage() + "\n");
}
System.out.println("程序繼續執行,這句話會被打印\n");
}
複製代碼
用戶能夠手動經過ThrowNew函數拋出異常,一樣能夠被Java代碼捕獲:spa
//異常處理
JNIEXPORT void JNICALL Java_com_test_JniTest_testException
(JNIEnv * env, jobject jobj){
jclass clz = (*env)->GetObjectClass(env, jobj);
//屬性名字不當心寫錯了,拿到的是空的jfieldID
jfieldID fid = (*env)->GetFieldID(env, clz, "key1", "Ljava/lang/String;");
jthrowable err = (*env)->ExceptionOccurred(env);
if (err != NULL){
//手動清空異常信息,保證Java代碼可以繼續執行
(*env)->ExceptionClear(env);
//提供補救措施,例如獲取另一個屬性
fid = (*env)->GetFieldID(env, clz, "key", "Ljava/lang/String;");
}
jstring key = (*env)->GetObjectField(env, jobj, fid);
char* c_str = (*env)->GetStringUTFChars(env, key, NULL);
//參數不正確,程序員本身拋出異常,能夠在Java中捕獲
if (_stricmp(c_str,"efg") != 0){
jclass err_clz = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
(*env)->ThrowNew(env, err_clz, "key value is invalid!");
}
}
複製代碼
測試代碼以下:code
public static void main(String[] args) {
JniTest test = new JniTest();
try {
test.testException();
System.out.println("JNI手動拋出了異常,Java不會繼續執行,這句話不會被打印\n");
} catch (Exception e) {
System.out.println("捕獲到JNI手動拋出的異常,這句話會被打印:" + e.getMessage() + "\n");
}
System.out.println("程序繼續執行,這句話會被打印\n");
}
複製代碼
####異常處理總結get
JNI本身拋出的異常,是Error類型,Java能夠經過Throwable或者Error來捕得到到,捕獲異常後Java代碼能夠繼續執行下去。在C層能夠清空(ExceptionClear),保證try中的代碼Java代碼繼續執行,而且最好要提供補救措施,確保JNI層代碼正常繼續運行。 用戶經過ThrowNew手動拋出的異常,一樣能夠在Java層捕捉獲得。