为什么不打印异常?

时间:2012-05-09 07:52:18

标签: java c exception-handling java-native-interface

以下是 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

为什么?

这两个陈述的作用是什么?为什么在没有这两个陈述的情况下不会打印出异常?

2 个答案:

答案 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程序员必须   发生异常后显式实现控制流程。

来自JNI documentation on exceptions

答案 1 :(得分:0)

根据the documentationExceptionDescribe

  

将堆栈的异常和回溯打印到系统错误报告通道,例如stderr。这是一个为调试提供的便利例程。

ExceptionClear

  

清除当前正在抛出的任何异常。如果当前没有抛出异常,则此例程无效。

这通常不是你想要的。我建议以NPE为原因创建IllegalArgumentException。在Java中,你会这样写:

throw new IllegalArgumentException( "thrown from c code", exc );

这样,内部和外部异常(包括堆栈跟踪)在Java级别可用,您可以在其中检查它们。