Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
应该在JNI接口中抛出泛型异常还是专用异常? 脚本 java代码库使用C++库。实现JNI接口是为了让API使用Java调用访问本机方法_Java_C++_Exception_Java Native Interface - Fatal编程技术网

应该在JNI接口中抛出泛型异常还是专用异常? 脚本 java代码库使用C++库。实现JNI接口是为了让API使用Java调用访问本机方法

应该在JNI接口中抛出泛型异常还是专用异常? 脚本 java代码库使用C++库。实现JNI接口是为了让API使用Java调用访问本机方法,java,c++,exception,java-native-interface,Java,C++,Exception,Java Native Interface,到目前为止,实现这一点的方法是在Java端使用函数: private static native void useFancyNativeFunction() throws SomeCustomException; JNI头文件中相应的方法包括错误处理,在需要时会抛出Java异常: try { // do amazing C++ things } catch ( const std::runtime_error& e ) { jclass Exception = env-

到目前为止,实现这一点的方法是在Java端使用函数:

private static native void useFancyNativeFunction() throws SomeCustomException;
JNI头文件中相应的方法包括错误处理,在需要时会抛出Java异常:

try
{
    // do amazing C++ things
}
catch ( const std::runtime_error& e )
{
    jclass Exception = env->FindClass( "util/somestuff/SomeCustomException" );
    env->ThrowNew( Exception, e.what() );
}
这意味着,如果在本机代码的特定块中引发运行时异常,则会在JVM封装的应用程序中引发和处理自定义Java异常

问题: 这引发了一场有趣的讨论,但尚未解决:


在此上下文中引发自定义异常意味着我们在JNI接口实现和特定Java代码库之间创建依赖关系。另一种方法是本机抛出泛型Java异常,然后通过Java代码捕获它们,然后抛出专用异常

因此,在给定的场景中,有两种选择:

  • 以本机方式引发专门的自定义Java异常:
  • 本机抛出泛型Java异常,在Java类中捕获它,作为专用异常重新抛出:
  • 首选哪一种?为什么

    补充资料
    • 在我们的例子中,对于两个版本都没有缺点,因为只有一个java代码库和一个C++代码库。JNI接口不需要重用
    • 依赖项只存在于接口本身中,而不存在于库中。后者正在被我们重用,但是没有涉及Java
    • 这两种选择都不太可能对我们产生重大影响。我只是出于兴趣而问

    主要的问题是您是想自己重用本机库,还是总是将其与Java包装器捆绑在一起

    通常,Java包装器本身是有意义的,与异常问题无关,它使本机功能看起来更像Java

    异常对象的角色 异常对象用于与调用方(调用堆栈上的某个位置,捕获异常)通信某些方法调用失败的原因。对于典型的代码,这个原因是不相关的(1),了解故障并能够生成一个合理的日志条目以及一条消息给用户就足够了

    来自本机代码的通信失败 <>您选择通过C++顶级层创建和抛出java异常来与本地代码通信失败,并创建对java异常系统和您选择使用的特定异常类的依赖性。

    我看到一些选择:

    • 使用Java标准异常,如
      RuntimeException
      。我们可以相信它将永远存在,这样依赖性就不会产生任何问题
    • 使用您自己的异常类型,如
      MyWonderfullLibraryException
      。我建议不要这样命名。这并不是描述故障原因,而是描述故障的位置。您必须确保异常类在Java包装器库中可用
    • 使用自己的异常类型,如
      NativeCppException
      。从技术上讲,这与 在前面的选择中,IMHO更好地将失败原因描述为Java计算模型中无法适当描述的原因
    • 在不创建Java异常的情况下,从本机代码通信故障,例如通过特殊故障返回值。这可能比您当前的方法更容易(而且性能更高,创建的代码依赖性更少)
    与用户代码通信失败 用户代码应该在发生故障时看到一个异常,该异常描述了故障的原因(主要用于日志记录)

    在您的情况下,原因隐藏在文本中的某个地方,该代码来自C++ <代码> RunTimeOrthEngult。您可能会尝试将其映射到不同的适当Java异常类型,但“您不需要它(YAGNI)”

    <>我首选的选择是“代码> NATEVECPPExpAc/Cuth>,总结C++世界中可能发生的一切。有些来电者可能有足够的勇气捕捉到这样的异常,可能只有在他有一个非本地的替代品可用的情况下

    (脚注1)

    我知道对于个别异常类型的重要性有不同的观点,但我还没有找到一个令人信服的论据来证明在野外经常看到的异常类型层次结构极其复杂

    创建异常类型是为了供代码的某些部分使用,否则这是典型的YAGNI情况

    关于内部调用的失败,方法通常分为三类:

  • 方法没有回退策略,所以在某些内部故障的情况下,整个方法都会失败。通常,这些方法允许异常在不进行干预的情况下通过
  • 方法有一个回退策略,允许即使在某些内部调用失败后也能成功,通常是通过重试或切换到其他执行路径。如果存在这样一种回退策略,那么使用它通常是有意义的,与失败原因无关。这些方法捕获特定块中出现的所有异常,然后激活回退,与故障原因无关
  • 方法具有只能在特定情况下应用的回退策略,并且可以通过异常类型来区分这些情况。这些方法只捕获某些特定的异常类型,然后激活相应的回退
    • 绝大多数方法都属于第一类(或者应该属于第一类,不是设计过度了吗)

    • 对于一些方法,开发人员创建了回退策略。大多数情况下,不仅针对特定的失败,而且针对任何失败,尝试这种策略都是无害的

    • 在极少数情况下,故障原因对selec很重要
      // Java caller
      try
      {
          useFancyNativeFunction();
      }
      catch( SomeCustomException e )
      {
          // treat custom exception directly here
      }
      
      // Java native call
      private static native void useFancyNativeFunction() throws SomeCustomException;
      
      // C++ JNI header
      try
      {
          // do amazing C++ things
      }
      catch ( const std::runtime_error& e )
      {
          jclass Exception = env->FindClass( "util/somestuff/SomeCustomException" );
          env->ThrowNew( Exception, e.what() );
      }
      
      // Java caller
      try
      {
          useFancyNativeFunction();
      }
      catch( RuntimeException e )
      {
          // catch generic, throw specialized, handle elsewhere
          throw new SomeCustomException( e.getMessage() );
      }
      
      // Java native call
      private static native void useFancyNativeFunction() throws RuntimeException;
      
      // C++ JNI header
      try
      {
          // do amazing C++ things
      }
      catch ( const std::runtime_error& e )
      {
          jclass Exception = env->FindClass( "java/lang/RuntimeException" );
          env->ThrowNew( Exception, e.what() );
      }