应将C/C++错误码转换为Java自定义异常NativeExecutionException,通过JNI的FindClass、GetMethodID、NewObject和Throw组合抛出带错误码的异常实例,并确保不调用ExceptionClear或继续执行逻辑。

<p>在 Java 中通过 JNI 调用 C/C++ 本地方法时,若底层发生错误(如内存分配失败、系统调用返回 errno、自定义业务错误),不应直接让 JVM 崩溃或抛出模糊的 <code>RuntimeException</code>,而应将 C/C++ 错误码转换为结构化的 Java 异常,比如自定义的 <code>NativeExecutionException</code>。关键在于:C 层捕获错误 → 封装错误码与上下文信息 → 主动触发 Java 异常抛出。</p>
<H3>定义 NativeExecutionException 类</H3>
<p>先在 Java 层定义一个带错误码、错误消息和可选原始上下文的运行时异常:</p>
<p><font color="#888"><!-- 示例 --></font></p>
<p><strong>public class NativeExecutionException extends RuntimeException {</strong><br>
<strong>private final int errorCode;</strong><br>
<strong>public NativeExecutionException(int errorCode, String message) {</strong><br>
<strong>super(message);</strong><br>
<strong>this.errorCode = errorCode;</strong><br>
<strong>}</strong><br>
<strong>public int getErrorCode() { return errorCode; }</strong><br>
<strong>}</strong></p>
<H3>在 JNI 函数中主动抛出 Java 异常</H3>
<p>C/C++ 层不能直接“throw”,需借助 JNI 接口:<code>FindClass</code> 获取异常类,<code>NewStringUTF</code> 构造消息,<code>ThrowNew</code> 触发抛出。注意:抛出后应立即返回,避免后续逻辑干扰 JVM 状态。</p>
<ul>
<li>检查本地函数返回值或 errno,确定是否出错</li>
<li>调用 <code>env->FindClass("com/example/NativeExecutionException")</code> 获取 Class 对象</li>
<li>用 <code>env->NewStringUTF("Failed to open device: ENOENT")</code> 创建消息字符串</li>
<li>调用 <code>env->ThrowNew(clazz, msgStr)</code> 抛出异常</li>
<li>函数返回前确保不执行可能崩溃的代码(如解引用空指针)</li>
</ul>
<H3>传递错误码到 Java 异常构造器</H3>
<p>JNI 不支持直接调用带 int 参数的异常构造器,需改用反射方式或预设构造器签名。推荐做法是:在 Java 异常类中提供接受 <code>(int, String)</code> 的构造器,并在 JNI 中通过 <code>GetMethodID</code> + <code>NewObject</code> + <code>Throw</code> 组合实现完整对象抛出:</p>
<ul>
<li>获取构造方法 ID:<code>jmethodID ctor = env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");</code></li>
<li>创建 Java 字符串:<code>jstring msg = env->NewStringUTF("Invalid handle");</code></li>
<li>新建异常实例:<code>jthrowable ex = (jthrowable)env->NewObject(clazz, ctor, 999, msg);</code></li>
<li>抛出:<code>env->Throw(ex);</code></li>
<li>注意释放局部引用(如 <code>msg</code>, <code>ex</code>)避免内存泄漏</li>
</ul>
<H3>确保异常不被 JVM 吞掉或静默忽略</H3>
<p>JNI 函数返回后,JVM 会检测是否有待处理异常。但若 Java 调用方未显式检查或 try-catch,异常会上抛。需注意:</p>
<ul>
<li>不要在 JNI 函数里调用 <code>ExceptionClear()</code>,否则会清除刚抛出的异常</li>
<li>避免在抛出异常后继续执行 JNI 逻辑(如调用 <code>ReleaseStringUTFChars</code> 但未检查是否成功)</li>
<li>Java 调用侧应明确捕获 <code>NativeExecutionException</code> 并根据 <code>getErrorCode()</code> 分支处理</li>
<li>可在 JNI 库初始化时缓存 <code>Class</code> 和 <code>MethodID</code>,提升性能并减少查找失败风险</li>
</ul>