<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ### 異常簡介 異常,顯而意見就是程序在運行期間沒有按照正常的程序邏輯執行,在執行過程當中出現了某種錯誤,導致程序崩潰。在Java中異常分為運行時異常(RuntimeException)和編譯時異常,在程序中有可能運行期間發生異常的邏輯我們會用try…catch…來處理,如果沒有處理的話,在運行期間發生異常就會導致程序奔潰。而編譯時異常是在編譯期間就必須處理的。本章主要介紹運行時異常。 **示例1:** ~~~ // 運行時異常 public static void exceptionCallback() { int a = 20 / 0; System.out.println("--->" + a); } ~~~ **示例2:** ~~~ // 編譯期間異常 public static void testException() throws Exception { // ... System.out.println("testException() invoked!"); } public static void main(String[] args) { exceptionCallback(); try { testException(); } catch (Exception e) { e.printStackTrace(); } // .... } ~~~ ~~~ 在示例2中,testException方法聲明時顯示拋出了一個java.lang.Exception異常,所以在程序調用的地方必須用try...catch處理。 ~~~ 大家都知道,如果示例2中main方法執行到調用exceptionCallback方法時,方法第一行有一個除0的操作,因此該方法會拋出`java.lang.ArithmeticException`數學異常,而在main方法調用的時候并沒有處理這個函數在運行時可能會發生的異常,所以會導致程序立即結束,而后面的代碼`try{testException();}catch(Exception e) {e.printStackTrace();}`都不會被執行。運行示例2程序的你會看到下面的結果: ~~~ Exception in thread "main" java.lang.ArithmeticException: / by zero at com.study.jnilearn.JNIException.exceptionCallback(JNIException.java:8) at com.study.jnilearn.JNIException.main(JNIException.java:22) ~~~ 我們改進一下上面這個程序: ~~~ public static void main(String[] args) { try { exceptionCallback(); } catch (Exception e) { e.printStackTrace(); } try { testException(); } catch (Exception e) { e.printStackTrace(); } } ~~~ 這時我們運行程序,調用`exceptionCallback`方法時會引發`java.lang.ArithmeticException: / by zero`異常,由于我們用try…catch塊顯示處理了異常,所以程序會繼續往下執行,調用testException()函數,打印`testException() invoked!`。運行結果如下所示: ~~~ java.lang.ArithmeticException: / by zero at com.study.jnilearn.JNIException.exceptionCallback(JNIException.java:8) at com.study.jnilearn.JNIException.main(JNIException.java:24) testException() invoked! ~~~ ### Java與JNI處理異常的區別 下面來小結一下: 1、在Java中如果覺得某段邏輯可能會引發異常,用try…catch機制來捕獲并處理異常即可 2、如果在Java中發生運行時異常,沒有使用try…catch來捕獲,會導致程序直接奔潰退出,**后續的代碼都不會被執行** 3、編譯時異常,是在方法聲明時顯示用throw聲明了某一個異常,編譯器要求在調用的時候必須顯示捕獲處理 `public static void testException() throws Exception {}` 上面這幾點,寫過Java的朋友都知道,而且很簡單,但我為什么還要拿出來說呢,其實我想重點說明的是,在JNI中發生的異常和Java完全不一樣。***我們在寫JNI程序的時候,JNI沒有像Java一樣有try…catch…final這樣的異常處理機制,面且在本地代碼中調用某個JNI接口時如果發生了異常,后續的本地代碼不會立即停止執行,而會繼續往下執行后面的代碼。*** ### 異常處理示例 **示例3:** 這個例子在main中調用了doit本地方法,在本地方法中會回調`exceptionCallback`方法,該方法中會引發一個除0的運行時異常`java.lang.ArithmeticException`,我們通過這個示例來學習在JNI中如何來正確處理這種異常。 ~~~ package com.study.jnilearn; public class JNIException { public static native void doit(); public static void exceptionCallback() { int a = 20 / 0; System.out.println("--->" + a); } public static void normalCallback() { System.out.println("In Java: invoke normalCallback."); } public static void main(String[] args) { doit(); } static { System.loadLibrary("JNIException"); } } ~~~ ~~~ /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_study_jnilearn_JNIException */ #ifndef _Included_com_study_jnilearn_JNIException #define _Included_com_study_jnilearn_JNIException #ifdef __cplusplus extern "C" { #endif /* * Class: com_study_jnilearn_JNIException * Method: doit * Signature: ()V */ JNIEXPORT void JNICALL Java_com_study_jnilearn_JNIException_doit (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif // JNIException.c #include "com_study_jnilearn_JNIException.h" #include <stdio.h> JNIEXPORT void JNICALL Java_com_study_jnilearn_JNIException_doit(JNIEnv *env, jclass cls) { jthrowable exc = NULL; jmethodID mid = (*env)->GetStaticMethodID(env,cls,"exceptionCallback","()V"); if (mid != NULL) { (*env)->CallStaticVoidMethod(env,cls,mid); } printf("In C: Java_com_study_jnilearn_JNIException_doit-->called!!!!"); if ((*env)->ExceptionCheck(env)) { // 檢查JNI調用是否有引發異常 (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); // 清除引發的異常,在Java層不會打印異常的堆棧信息 (*env)->ThrowNew(env,(*env)->FindClass(env,"java/lang/Exception"),"JNI拋出的異常!"); //return; } mid = (*env)->GetStaticMethodID(env,cls,"normalCallback","()V"); if (mid != NULL) { (*env)->CallStaticVoidMethod(env,cls,mid); } } ~~~ 程序運行結果如下: ~~~ Exception in thread "main" java.lang.ArithmeticException: / by zero at com.study.jnilearn.JNIException.exceptionCallback(JNIException.java:8) at com.study.jnilearn.JNIException.doit(Native Method) at com.study.jnilearn.JNIException.main(JNIException.java:17) Exception in thread "main" java.lang.Exception: JNI拋出的異常! at com.study.jnilearn.JNIException.doit(Native Method) In Java: invoke normalCallback. at com.study.jnilearn.JNIException.main(JNIException.java:17) In C: Java_com_study_jnilearn_JNIException_doit-->called!!!! ~~~ 在Main方法中調用doit本地方法后,程序的控制權即交給了JNI,在doit的本地方法中回調exceptionCallback方法,引發了一個`java.lang.ArithmeticException`異常,但本地接口并不會馬上退出,而是會繼續執行后面的代碼,所以我們在調用完一個任何一個JNI接口之后,必須要做的一件事情就是檢查這次JNI調用是否發生了異常,如果發生了異常不處理,而繼續讓程序執行后面的邏輯,將會產生不可預知的后果。在本例中,我們調用了JNI的`ExceptionCheck`函數檢查最近一次JNi調用是否發生了異常,如果有異常這個函數返回JNI_TRUE,否則返回JNI_FALSE。當檢測到異常時,我們調用`ExceptionDescribe`函數打印這個異常的堆棧信息,然后再調用`ExceptionClear`函數清除異常堆棧信息的緩沖區(如果不清除,后面調用ThrowNew拋出的異常堆棧信息會覆蓋前面的異常信息),最后調用`ThrowNew`函數手動拋出一個java.lang.Exception異常。但在JNI中拋出未捕獲的異常與Java的異常處理機制不一樣,在JNI中并不會立即終止本地方法的執行,而是繼續執行后面的代碼。這種情況需要我們手動來處理。在例中的38行,如果你不用return馬上退出方法的話,37行ThrowNew后面的代碼依然會繼續執行,如程序運行的結果一樣,仍然會回調`normalCallback`方法,打印出:invoke normalCallback. 異常檢查JNI還提供了另外一個接口,`ExceptionOccurred`,如果檢測有異常發生時,該函數會返回一個指向當前異常的引用。作用和`ExceptionCheck`一樣,兩者的區別在于返回值不一樣。我們改造一下上面的例子: ~~~ // .... jthrowable exc = NULL; exc = (*env)->ExceptionOccurred(env); // 返回一個指向當前異常對象的引用 if (exc) { (*env)->ExceptionDescribe(env); // 打印Java層拋出的異常堆棧信息 (*env)->ExceptionClear(env); // 清除異常信息 // 拋出我們自己的異常處理 jclass newExcCls; newExcCls = (*env)->FindClass(env,"java/lang/Exception"); if (newExcCls == NULL) { return; } (*env)->ThrowNew(env, newExcCls, "throw from C Code."); } // .... ~~~ ### 寫一個拋出異常的工具類 當需要拋出自己的異常處理邏輯時,需要二步,調用FindClass找到異常處理類,然后調用ThrowNew拋出一個異常。為了簡化操作步聚,我們寫一個工具函數,根據一個異常類名專門用來生成一個指定名字的異常: ~~~ void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) { // 查找異常類 jclass cls = (*env)->FindClass(env, name); /* 如果這個異常類沒有找到,VM會拋出一個NowClassDefFoundError異常 */ if (cls != NULL) { (*env)->ThrowNew(env, cls, msg); // 拋出指定名字的異常 } /* 釋放局部引用 */ (*env)->DeleteLocalRef(env, cls); } ~~~ ### 異常發生后釋放資源 在異常發生后,釋放資源是一件很重要的事情。下面的例子中,調用 GetStringChars 函數后,如果后面的代碼發生異常,要記得調用 ReleaseStringChars 釋放資源。 ~~~ JNIEXPORT void JNICALL Java_pkg_Cls_f(JNIEnv *env, jclass cls, jstring jstr) { const jchar *cstr = (*env)->GetStringChars(env, jstr); if (c_str == NULL) { return; } ... if ((*env)->ExceptionCheck(env)) { /* 異常檢查 */ (*env)->ReleaseStringChars(env, jstr, cstr); // 發生異常后釋放前面所分配的內存 return; } ... /* 正常返回 */ (*env)->ReleaseStringChars(env, jstr, cstr); } ~~~ ### 總結 1、當調用一個JNI函數后,必須先檢查、處理、清除異常后再做其它 JNI 函數調用,否則會產生不可預知的結果。 2、一旦發生異常,立即返回,讓調用者處理這個異常。或 調用 ExceptionClear 清除異常,然后執行自己的異常處理代碼。 3、異常處理的相關JNI函數總結: 1> ExceptionCheck:檢查是否發生了異常,若有異常返回JNI_TRUE,否則返回JNI_FALSE 2> ExceptionOccurred:檢查是否發生了異常,若用異常返回該異常的引用,否則返回NULL 3> ExceptionDescribe:打印異常的堆棧信息 4> ExceptionClear:清除異常堆棧信息 5> ThrowNew:在當前線程觸發一個異常,并自定義輸出異常信息 `jint (JNICALL *ThrowNew) (JNIEnv *env, jclass clazz, const char *msg);` 6> Throw:丟棄一個現有的異常對象,在當前線程觸發一個新的異常 `jint (JNICALL *Throw) (JNIEnv *env, jthrowable obj);` 7> FatalError:致命異常,用于輸出一個異常信息,并終止當前VM實例(即退出程序) `void (JNICALL *FatalError) (JNIEnv *env, const char *msg);`
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看