在android的JNIHelp.h文件中声明四种可以向JVM抛异常的函数:

int jniThrowException(JNIEnv* env, 
   const char* className,
   const char*
 
  
int jniThrowNullPointerException(JNIEnv* env, 
   char*
 
  
int jniThrowIOException(JNIEnv* env, 
   int errnum)
  
 
  
int jniThrowRuntimeException(JNIEnv* env, 
   const char*
 
  
注意:虽然 
   const char* className
   它是字符串,但是它是要传到中使用,所以它必须和某个类相对应的。
 
 
以上4个函数的定义是JNIHelp.c文件中进行的。查看源码你会发现
  jniThrowNullPointerException
  、
  jniThrowRuntimeException
  、
  jniThrowIOException
  其实就是个特殊的jniThrowException。
  其实它们是const char*
  className
  参数分别为"
  java/lang/NullPointerException
  "、
  "java/lang/RuntimeException
  "、"
  java/IO/IOException
  "的jniThrowException。
 
 
它们的使用也很简单,具体可以参照下面的示例代码。
 
 
另外注意,这里的抛异常函数并不是在抛异常的同时退出当前函数,而是在函数最终返回时,才真正的抛出异常。
 
 

   示例1
  
 
  

   android_database_SQLiteQuery.cpp文件中的native_fill_window函数
  
 
  
static jint
    native_fill_window(JNIEnv* env, jobject object, jobject javaWindow, 
   jint
    startPos,
    jint
    offsetParam)
 
  

   {
  
 
  
//略
 
  
    if (statement == NULL) {
 
  
        LOGE("Invalid statement in fillWindow()");
 
  
        jniThrowException(env, "java/lang/IllegalStateException",
 
  
                          "Attempting to access a deactivated, closed, or empty cursor");
 
  
        
   return
    0;
 
  
    }
 
  

 
  
    // Only do the binding if there is a valid offsetParam. If no binding needs to be done
 
  
    // offsetParam will be set to 0, an invliad value.
 
  
   
    if
   (offsetParam > 0) {
 
  
        // Bind the offset parameter, telling the program which row to start with
 
  
        err = sqlite3_bind_int(statement, offsetParam, startPos);
 
  
        
   if
    (err != SQLITE_OK) {
 
  
            LOGE("Unable to bind offset position, offsetParam = %d", offsetParam);
 
  
            jniThrowException(env, "java/lang/IllegalArgumentException",
 
  
                              sqlite3_errmsg(GET_HANDLE(env, object)));
 
  
            
   return 
   0;
 
  
        }
 
  
        LOG_WINDOW("Bound to startPos %d", startPos);
 
  
    } else {
 
  
        LOG_WINDOW("Not binding to startPos %d", startPos);
 
  
    }
 
  

 
  
    // Get the native window
 
  
    window = get_window_from_object(env, javaWindow);
 
  
    if (!window) {
 
  
        LOGE("Invalid CursorWindow");
 
  
       
    jniThrowException(env, "java/lang/IllegalArgumentException","Bad CursorWindow");
 
  
        
   return
    0;
 
  
    }
 
  
    LOG_WINDOW("Window: numRows = %d, size = %d, freeSpace = %d", window->getNumRows(), window->size(), window->freeSpace());
 
  

 
  
    numColumns = sqlite3_column_count(statement);
 
  
    if (!window->setNumColumns(numColumns)) {
 
  
        LOGE("Failed to change column count from %d to %d", window->getNumColumns(), numColumns);
 
  
       
    jniThrowException(env, "java/lang/IllegalStateException", "numColumns mismatch");
 
  
        
   return
    0;
 
  
    }
 
  
//略    
 
  

   }
  
 
  

   示例2
  
 
  

   android_util_EventLog.cpp中的android_util_EventLog_readEvents函数
  
 
static void
 
 

                                               jintArray tags,
 
 
 

                                               jobject out) {
 
 
 

      if (tags == NULL || out == NULL) {
 
 
 
jniThrowException(env, "java/lang/NullPointerException", NULL);
 
 
 return;
 
 
 

      }
 
 
 

  
 
 

      int fd = open("/dev/" LOGGER_LOG_EVENTS, O_RDONLY | O_NONBLOCK);
 
 
 
if
 
 
jniThrowIOException(env, errno);
 
 

          return;
 
 
 

      }
 
 
 

  
 
 

      jsize tagLength = env->GetArrayLength(tags);
 
 
 

      jint *tagValues = env->GetIntArrayElements(tags, NULL);
 
 
 

  
 
 

      uint8_t buf[LOGGER_ENTRY_MAX_LEN];
 
 
 

      struct timeval timeout = {0, 0};
 
 
 

      fd_set readset;
 
 
 

      FD_ZERO(&readset);
 
 
 

  
 
 
for (;;) {
 
 
 

          // Use a short select() to try to avoid problems hanging on read().
 
 
 

          // This means we block for 5ms at the end of the log -- oh well.
 
 
 

          timeout.tv_usec = 5000;
 
 
 

          FD_SET(fd, &readset);
 
 
 
int
 
 

          if (r == 0) {
 
 
 

              break;  // no more events
 
 
 

          } else if (r < 0 && errno == EINTR) {
 
 
 

              continue;  // interrupted by signal, try again
 
 
 

          } else if (r < 0) {
 
 
 
jniThrowIOException(env, errno);  // Will throw on return
 
 

              break;
 
 
 

          }
 
 
 

  
 
 

          int len = read(fd, buf, sizeof(buf));
 
 
 

          if (len == 0 || (len < 0 && errno == EAGAIN)) {
 
 
 

              break;  // no more events
 
 
 

          } else if (len < 0 && errno == EINTR) {
 
 
 

              continue;  // interrupted by signal, try again
 
 
 

          } else if (len < 0) {
 
 
 
 jniThrowIOException(env, errno);  // Will throw on return
 
 

              break;
 
 
 

          } else if ((size_t) len < sizeof(logger_entry) + sizeof(int32_t)) {
 
 
 
jniThrowException(env, "java/io/IOException", "Event too short");
 
 

              break;
 
 
 

          }
 
 
 
//略
 
 
 

      }
 
 
 

      close(fd);
 
 
 

      env->ReleaseIntArrayElements(tags, tagValues, 0);
 
 
 

  }