以下是 java 代码,旁边是 c 代码:
package Package;
public class CatchThrow {
private native void doit() throws IllegalArgumentException;
private void callBack() throws NullPointerException {
System.out.println("In call-back !");
throw new NullPointerException("CatchThrow.callBack");
}
public static void main(String args[]) {
CatchThrow c = new CatchThrow();
try {
c.doit();
} catch(Exception exc) {
System.out.println("\nIn Java : \n\t" + exc);
}
}
static {
System.loadLibrary("CatchThrow");
}
}
C代码:
#include "stdio.h"
#include "Package_CatchThrow.h"
void Java_Package_CatchThrow_doit
(JNIEnv *env, jobject obj) {
jthrowable exc;
jclass cls = (*env)->GetObjectClass(env,obj);
jmethodID mid = (*env)->GetMethodID(env,cls,"callBack","()V");
if(mid == NULL) {
return;
}
(*env)->CallVoidMethod(env,obj,mid); // call the java method that throws NullPointerException
printf("After the call to Call-Back !");
exc = (*env)->ExceptionOccurred(env);
if(exc) {
jclass newExcCls;
printf("\n");
//(*env)->ExceptionDescribe(env); ----> NOTE THE COMMENTED STATEMENT
//(*env)->ExceptionClear(env); -----> NOTE THE COMMENTED STATEMENT
newExcCls = (*env)->FindClass(env,"java/lang/IllegalArgumentException");
if(newExcCls == NULL) {
return;
}
(*env)->ThrowNew(env,newExcCls,"thrown from c code");
}
}
当我构建并运行上述程序时,我得到以下输出:
In call-back !
After the call to Call-Back !
In Java :
java.lang.IllegalArgumentException: thrown from c code
从输出: C代码调用java函数 callBack 。在那里打印第一个语句。在呼叫返回呼叫旁边的语句,即After the call to Call-Back !
被打印。但是java函数 callBack 中的语句throw new NullPointerException("CatchThrow.callBack");
发生了什么?为什么不打印例外?
但是如果我从声明中删除评论
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
评论说,我得到了所需的输出:
In call-back !
After the call to Call-Back !
Exception in thread "main" java.lang.NullPointerException: CatchThrow.callBack
at Package.CatchThrow.callBack(CatchThrow.java:14)
at Package.CatchThrow.doit(Native Method)
at Package.CatchThrow.main(CatchThrow.java:20)
In Java :
java.lang.IllegalArgumentException: thrown from c code
为什么?
这两个陈述的作用是什么?为什么在没有这两个陈述的情况下不会打印出异常?
答案 0 :(得分:2)
您的new NullPointerException("CatchThrow.callBack");
永远不会触及Java运行时,并且在JNI空间中完全处理。
因此,除非您调用JNI ExceptionDescribe函数,否则不会打印任何异常详细信息:
(*env)->ExceptionDescribe(env);
您无法从JNI返回多个异常,因此在Java运行时中返回到try / catch块的唯一异常信息是您稍后创建的异常信息:
(*env)->ThrowNew(env,newExcCls,"thrown from c code");
通过JNI引发的待处理异常(通过调用ThrowNew,for 示例)不会立即中断本机方法执行。 这与Java编程中的异常行为有所不同 语言。在Java编程中抛出异常时 语言,虚拟机自动传输控制流 到最近的封闭的try / catch语句匹配 异常类型。然后,虚拟机将清除挂起的异常 并执行异常处理程序。相比之下,JNI程序员必须 发生异常后显式实现控制流程。
答案 1 :(得分:0)
根据the documentation,ExceptionDescribe
将堆栈的异常和回溯打印到系统错误报告通道,例如
stderr
。这是一个为调试提供的便利例程。
ExceptionClear
:
清除当前正在抛出的任何异常。如果当前没有抛出异常,则此例程无效。
这通常不是你想要的。我建议以NPE为原因创建IllegalArgumentException
。在Java中,你会这样写:
throw new IllegalArgumentException( "thrown from c code", exc );
这样,内部和外部异常(包括堆栈跟踪)在Java级别可用,您可以在其中检查它们。