JNI/NDK开发指南(十一)——JNI异常处理

来源:互联网 发布:纸质笔记本 性价比知乎 编辑:程序博客网 时间:2024/06/06 13:22

转载请注明出处:http://blog.csdn.net/xyang81/article/details/45770551

异常简介

异常,显而意见就是程序在运行期间没有按照正常的程序逻辑执行,在执行过程当中出现了某种错误,导致程序崩溃。在Java中异常分为运行时异常(RuntimeException)和编译时异常,在程序中有可能运行期间发生异常的逻辑我们会用try…catch…来处理,如果没有处理的话,在运行期间发生异常就会导致程序奔溃。而编译时异常是在编译期间就必须处理的。本章主要介绍运行时异常。 
示例1:

<code class="language-Java hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 运行时异常</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">exceptionCallback</span>() {    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> a = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span> / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;    System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"--->"</span> + a);}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

示例2:

<code class="language-Java hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 编译期间异常</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">testException</span>() throws Exception {    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span>    System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"testException() invoked!"</span>);}<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) {    exceptionCallback();     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> {        testException();    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) {        e.printStackTrace();    }    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ....</span>}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>
在示例2中,testException方法声明时显示抛出了一个java.lang.Exception异常,所以在程序调用的地方必须用try...catch处理。

大家都知道,如果示例2中main方法执行到调用exceptionCallback方法时,方法第一行有一个除0的操作,因此该方法会抛出java.lang.ArithmeticException数学异常,而在main方法调用的时候并没有处理这个函数在运行时可能会发生的异常,所以会导致程序立即结束,而后面的代码try{testException();}catch(Exception e) {e.printStackTrace();}都不会被执行。运行示例2程序的你会看到下面的结果:

<code class="language-Java hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Exception <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> thread <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"main"</span> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ArithmeticException</span>: / by zero    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.exceptionCallback</span>(JNIException<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>)    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.main</span>(JNIException<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">22</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

我们改进一下上面这个程序:

<code class="language-Java hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) {    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> {        exceptionCallback();    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) {        e.printStackTrace();    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> {        testException();    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) {        e.printStackTrace();    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

这时我们运行程序,调用exceptionCallback方法时会引发java.lang.ArithmeticException: / by zero异常,由于我们用try…catch块显示处理了异常,所以程序会继续往下执行,调用testException()函数,打印testException() invoked!。运行结果如下所示:

<code class="language-Java hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-label" style="box-sizing: border-box;">java.lang.ArithmeticException:</span> / by zero    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.exceptionCallback</span>(JNIException<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>)    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.main</span>(JNIException<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>)testException() invoked!</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

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中如何来正确处理这种异常。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> com.study.jnilearn;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">JNIException</span> {</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">native</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">doit</span>();    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">exceptionCallback</span>() {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> a = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span> / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"--->"</span> + a);    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">normalCallback</span>() {        System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"In Java: invoke normalCallback."</span>);    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) {        doit();    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> {        System.loadLibrary(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"JNIException"</span>);    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>
<code class="language-c hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* DO NOT EDIT THIS FILE - it is machine generated */</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <jni.h></span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* Header for class com_study_jnilearn_JNIException */</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#ifndef _Included_com_study_jnilearn_JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define _Included_com_study_jnilearn_JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#ifdef __cplusplus</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"C"</span> {<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#endif</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * Class:     com_study_jnilearn_JNIException * Method:    doit * Signature: ()V */</span>JNIEXPORT <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> JNICALL Java_com_study_jnilearn_JNIException_doit  (JNIEnv *, jclass);<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#ifdef __cplusplus</span>}<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#endif</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#endif</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// JNIException.c</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "com_study_jnilearn_JNIException.h"</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <stdio.h></span>JNIEXPORT <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> JNICALL Java_com_study_jnilearn_JNIException_doit(JNIEnv *env, jclass cls) {    jthrowable exc = NULL;    jmethodID mid = (*env)->GetStaticMethodID(env,cls,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"exceptionCallback"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"()V"</span>);    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mid != NULL) {        (*env)->CallStaticVoidMethod(env,cls,mid);    }    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"In C: Java_com_study_jnilearn_JNIException_doit-->called!!!!"</span>);    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((*env)->ExceptionCheck(env)) {  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 检查JNI调用是否有引发异常</span>        (*env)->ExceptionDescribe(env);        (*env)->ExceptionClear(env);        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 清除引发的异常,在Java层不会打印异常的堆栈信息</span>        (*env)->ThrowNew(env,(*env)->FindClass(env,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"java/lang/Exception"</span>),<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"JNI抛出的异常!"</span>);        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//return;</span>    }    mid = (*env)->GetStaticMethodID(env,cls,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"normalCallback"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"()V"</span>);    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mid != NULL) {        (*env)->CallStaticVoidMethod(env,cls,mid);    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li></ul>

程序运行结果如下:

<code class="language-Java hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Exception <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> thread <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"main"</span> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ArithmeticException</span>: / by zero    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.exceptionCallback</span>(JNIException<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>)    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.doit</span>(Native Method)    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.main</span>(JNIException<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">17</span>)Exception <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> thread <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"main"</span> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Exception</span>: JNI抛出的异常!    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.doit</span>(Native Method)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">In</span> Java: invoke normalCallback.    at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.study</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.jnilearn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.JNIException</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.main</span>(JNIException<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">17</span>)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">In</span> C: Java_com_study_jnilearn_JNIException_doit-->called!!!!</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

在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一样,两者的区别在于返回值不一样。我们改造一下上面的例子:

<code class="language-C hljs coffeescript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> ....jthrowable exc = NULL;<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-title" style="box-sizing: border-box;">exc</span> = <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(*env)</span>-></span>ExceptionOccurred(env);  <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> 返回一个指向当前异常对象的引用<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (exc) {    <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(*env)</span>-></span>ExceptionDescribe(env); <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> 打印Java层抛出的异常堆栈信息    <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(*env)</span>-></span>ExceptionClear(env);        <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> 清除异常信息    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> 抛出我们自己的异常处理    jclass newExcCls;    <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-title" style="box-sizing: border-box;">newExcCls</span> = <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(*env)</span>-></span>FindClass(env,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"java/lang/Exception"</span>);    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (newExcCls == NULL) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;    }    <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(*env)</span>-></span>ThrowNew(env, newExcCls, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"throw from C Code."</span>);}<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> ....</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>

写一个抛出异常的工具类

当需要抛出自己的异常处理逻辑时,需要二步,调用FindClass找到异常处理类,然后调用ThrowNew抛出一个异常。为了简化操作步聚,我们写一个工具函数,根据一个异常类名专门用来生成一个指定名字的异常:

<code class="language-C hljs coffeescript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-reserved" style="box-sizing: border-box;">void</span> JNU_ThrowByName(JNIEnv *env, <span class="hljs-reserved" style="box-sizing: border-box;">const</span> char *name, <span class="hljs-reserved" style="box-sizing: border-box;">const</span> char *msg) {     <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> 查找异常类     jclass <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-title" style="box-sizing: border-box;">cls</span> = <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(*env)</span>-></span>FindClass(env, name);     <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/* 如果这个异常类没有找到,VM会抛出一个NowClassDefFoundError异常 */</span>     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (cls != NULL) {         <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(*env)</span>-></span>ThrowNew(env, cls, msg);  <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> 抛出指定名字的异常     }     <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/* 释放局部引用 */</span>     <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(*env)</span>-></span>DeleteLocalRef(env, cls); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

异常发生后释放资源

在异常发生后,释放资源是一件很重要的事情。下面的例子中,调用 GetStringChars 函数后,如果后面的代码发生异常,要记得调用 ReleaseStringChars 释放资源。

<code class="language-C hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">JNIEXPORT void JNICALL Java_pkg_Cls_f(JNIEnv *env, jclass cls, jstring jstr) {     const jchar *cstr = (*env)->GetStringChars(env, jstr);     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (c_str == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>) {         <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;      }     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((*env)->ExceptionCheck(env)) { /* 异常检查 */         (*env)->ReleaseStringChars(env, jstr, cstr); // 发生异常后释放前面所分配的内存         <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;      }     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>     /* 正常返回 */     (*env)->ReleaseStringChars(env, jstr, cstr);}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

总结

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);

0 0