| Java Native Interface Programming

## Catching and Throwing Exceptions

> In Java, once an exception is thrown, the Virtual Machine automatically looks for the nearest enclosing exception handler, and unwinds the stack if necessary. The advantage of this style of exceptions is that the programmer does not have to care about unusual error cases for every operation in the program. Instead, the error conditions are propagated automatically to a location (the `catch` clause in Java) where the same class of error conditions can be handled in a centralized way.

> Although certain languages such as C++ support a similar notion of exception handling, there is no uniform and general way to throw and catch exceptions in native languages. The JNI therefore requires you to check for possible exceptions after calling JNI functions. The JNI also provides functions to throw Java exceptions, which can then be handled either by other parts of your native code, or by the Java Virtual Machine. After the native code catches and handles an exception, it can either clear the pending exception so that the computation may continue, or it can throw another exception for an outer exception handler.

> Many JNI functions may cause an exception to be thrown. For example, the `GetFieldID` function described in the previous section throws a `NoSuchFieldError` if the specified field does not exist. To simplify error checking, most JNI functions use a combination of error codes and Java exceptions to report error conditions. You may, for example, check if the `jfieldID` returned from `GetFieldID` is 0, instead of calling the JNI function `ExceptionOccurred`. When the result of `GetFieldID` is not 0, it is guaranteed that there is no pending exception.

> The remainder of the section illustrates how to catch and throw exceptions in native code. The example code is in `CatchThrow.java`.

> The `CatchThrow.main` method calls the native method. The native method, defined in `CatchThrow.c`, first invokes the Java method `CatchThrow.callback`:

>       jclass cls = (*env)->GetObjectClass(env, obj);
>       jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
>       jthrowable exc;
>       if (mid == 0)
>         return;
>       (*env)->CallVoidMethod(env, obj, mid);

> Note that since `CallVoidMethod` throws a `NullPointerException`, the native code can detect this exception after `CallVoidMethod` returns by calling `ExceptionOccurred`:

>       exc = (*env)->ExceptionOccurred(env);
>       if (exc) {

> This is how you can catch and handle an exception. In our example, we do not do much about the exception in `CatchThrow.c`, except use `ExceptionDescribe` to output some debugging message. It then throws an `IllegalArgumentException`. It is this `IllegalArgumentException` that the Java code which invoked the native method will see.

>         (*env)->ExceptionDescribe(env);
>         (*env)->ExceptionClear(env);

>         newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
>         if (newExcCls == 0) /* Unable to find the new exception class, give up. */
>           return;
>         (*env)->ThrowNew(env, newExcCls, "thrown from C code");

> `ThrowNew` constructs an exception object from the given exception class and message string and posts the exception in the current thread.

> Note that it is extremely important to check, handle, and clear the pending exception before we call the subsequent JNI functions. Calling arbitrary JNI functions with a pending exception may lead to unexpected results. Only a small number of JNI functions are safe to call when there is a pending exception. They include `ExpectionOccurred`, `ExceptionDescribe`, and `ExceptionClear`.

| Java Native Interface Programming