Java 如何捕获静态初始值设定项块中引发的异常

Java 如何捕获静态初始值设定项块中引发的异常,java,exception,static,initialization,classloader,Java,Exception,Static,Initialization,Classloader,我编写了以下代码: static { /* Attempts to load JDBC driver */ try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { throw new DBConfigurationException("JDBC Driver not found.",

我编写了以下代码:

    static {
        /* Attempts to load JDBC driver */
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new DBConfigurationException("JDBC Driver not found.", e);
        }
        /* Attempts to load configuration */
        conf = loadConfiguration(); //this may throw some subclasses of RuntimeException
    }
因为我希望JDBC驱动程序和配置只加载一次

我想在创业时做一些类似的事情(我会尽量简化):

现在的问题是,如果发生异常,JVM将抛出ad
ExceptionInInitializerError
,而不会构造对象。 也许我仍然能够理解出了什么问题,捕捉到了
异常初始化错误(即使这听起来不对)并检查其原因(我仍然没有尝试这样做,但我认为这是可能的)

我需要该对象,因为如果异常是可恢复的(例如MissingConfigurationException),程序将不会退出,并且需要该对象

我应该避免使用静态初始值设定项吗? 我可以这样做:

private static final Configuration conf = null;

Constructor() {
    if (conf == null) {
        /* Attempts to load JDBC driver */
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new DBConfigurationException("JDBC Driver not found.", e);
        }
        /* Attempts to load configuration */
        conf = loadConfiguration();
    }
}
但即使这一条对我来说听起来也不正确:只有在第一次尝试使用时才会抛出异常(我知道会在启动时抛出,因为我必须进行检查),也就是说,当类加载时。因此,从理论上讲,第一种方法更为正确\

我该怎么办?哪种方式更正确


问题是,带有静态初始值设定项的类需要驱动程序和配置,因此在它们都可用之前不应使用它:\

为什么不在
main()
方法中检查这些条件,或者检查
main()
方法调用的某些条件?应用程序的入口点只能输入一次。一个简单的方法比静态初始化器和类加载器技巧要好得多

public static void main(String[] args) {
    if (!requirementsMet()) {
         System.exit(1);
    }
    //proceed with app...
}

private static boolean requirementsMet() {
     // check if DB driver can be loaded, and other non-recoverable errors
}

您可以使用单例类。e、 g

DBConfigProvider {
    private Configuration conf = null
    private DBConfigProvider() {
      /* Attempts to load JDBC driver */
      try {
          Class.forName("com.mysql.jdbc.Driver");
      } catch (ClassNotFoundException e) {
          throw new DBConfigurationException("JDBC Driver not found.", e);
      }
      /* Attempts to load configuration */
      conf = loadConfiguration(); //this may throw some subclasses of RuntimeException
    }

    private static DBConfigProvider instance = null;

    public static Configuration getConf() {
         if (instance == null) {
             instance = new DBConfigurationProvider();
         }

         return instance.conf;
    }
}

+1代表“欺骗”一词;)此外,应该或多或少地避免使用静态初始值设定项,因为如果静态初始值设定项失败,可能会出现奇怪的错误,例如
NoClassDefFound
错误。从不需要欺骗的角度来看,这很好,但它不会以模块化的方式隔离需求。我想这取决于应用程序的大小和您正在编写的内容。@TonyK。这取决于应用程序。如果它需要数据库访问才能运行,它应该在
main
线程中失败并终止。如果没有,那么它应该在其他地方失败,我同意。我同意布莱恩的评论。如果它需要数据库访问才能运行,则应该失败,否则将代码移到其他位置。@Brian。我的评论是关于将requirementsMet()放在何处……如果数据库是某种可能使用不同驱动程序的可插拔模块,那么围绕它的抽象是理想的。从main()调用它是可以的。根据定义,从
static{}
块抛出的异常会生成ExceptionInInitializer并标记该类不可用。这是应该的方式(加上或减去一个小的增量);顺便说一句,我应该如何使用它?如果我没有弄错的话,行“private static final Configuration conf=DBConfigProvider.getConf()”仍然会抛出
exceptionininitializerror
。为什么需要使用静态变量进行配置?我希望您在实际需要时调用DBConfigProvider.getConf()。使其成为单例的想法是,您只保留一个配置实例,同时“延迟”初始化它(在需要时)。因为作为负责连接到DB的类,它应该包含必要的细节(驱动程序和配置),并且能够在不假设其自身用法的情况下工作(例如,在调用方法getConnection()之前加载驱动程序并设置配置)。其他类应该在不知道这些细节的情况下调用其方法。(对不起,英语不好,我今天感觉阅读困难:D)
DBConfigProvider {
    private Configuration conf = null
    private DBConfigProvider() {
      /* Attempts to load JDBC driver */
      try {
          Class.forName("com.mysql.jdbc.Driver");
      } catch (ClassNotFoundException e) {
          throw new DBConfigurationException("JDBC Driver not found.", e);
      }
      /* Attempts to load configuration */
      conf = loadConfiguration(); //this may throw some subclasses of RuntimeException
    }

    private static DBConfigProvider instance = null;

    public static Configuration getConf() {
         if (instance == null) {
             instance = new DBConfigurationProvider();
         }

         return instance.conf;
    }
}