【问题标题】:why doesn't the exception get printed?为什么不打印异常?
【发布时间】:2012-05-09 07:52:17
【问题描述】:

下面是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"); 语句发生了什么?为什么它不打印异常?

但是如果我从语句中删除 cmets

(*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

为什么会这样?

这两个语句的作用是什么?为什么在没有这两条语句的情况下不打印异常?

【问题讨论】:

  • 面临同样的问题。我的 jni 代码在 GetObjectClass 旁边的 CallVoidMethod 中崩溃,而不是在函数 CallVoidMethod 中崩溃,这会导致 NullPointerException

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


【解决方案1】:

您的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,例如 示例)不会立即中断本机方法的执行。 这与 Java 编程中异常的行为方式不同 语。当Java编程中抛出异常时 语言,虚拟机自动转移控制流 到最近的封闭 try/catch 语句匹配 异常类型。然后虚拟机清除挂起的异常 并执行异常处理程序。相比之下,JNI 程序员必须 发生异常后显式实现控制流。

来自JNI documentation on exceptions

【讨论】:

  • 你能解释一下JNI空间是什么意思吗?
  • 当您调用 JNI 函数时,您不再处于 Java 虚拟机中——您处于本机 C 代码中,直到函数返回。 “Java™ 有一个清晰一致的异常处理策略,但 C/C++ 代码没有。因此,Java JNI 在检测到错误时不会抛出异常。JNI 不知道如何,甚至不知道,应用程序的本机代码可以处理它。”
【解决方案2】:

根据the documentationExceptionDescribe

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

ExceptionClear:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2021-11-04
    相关资源
    最近更新 更多