2

以下は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 !印刷されます。しかしthrow new NullPointerException("CatchThrow.callBack");、Java関数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つのステートメントの役割は何ですか?そして、これらの2つのステートメントがないのに、なぜ例外が出力されないのでしょうか。

4

2 に答える 2

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を呼び出すことによって)発生した保留中の例外は、ネイティブメソッドの実行をすぐには中断しません。これは、Javaプログラミング言語での例外の動作とは異なります。Javaプログラミング言語で例外がスローされると、仮想マシンは、例外タイプに一致する最も近い囲んでいるtry/catchステートメントに制御フローを自動的に転送します。次に、仮想マシンは保留中の例外をクリアし、例外ハンドラーを実行します。対照的に、JNIプログラマーは、例外が発生した後に制御フローを明示的に実装する必要があります。

例外に関するJNIドキュメントから

于 2012-05-09T08:11:48.553 に答える
0

ドキュメントによると、ExceptionDescribe

例外とスタックのバックトレースを、などのシステムエラー報告チャネルに出力しstderrます。これは、デバッグ用に提供されている便利なルーチンです。

ExceptionClear

現在スローされている例外をすべてクリアします。現在例外がスローされていない場合、このルーチンは効果がありません。

これは通常、あなたが望むものではありません。IllegalArgumentExceptionNPEを原因として作成することをお勧めします。Javaでは、次のように記述します。

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

このようにして、内部および外部の例外(スタックトレースを含む)をJavaレベルで使用して、それらを調べることができます。

于 2012-05-09T08:11:37.783 に答える