如何捕获静态初始化程序块中抛出的异常

时间:2012-09-06 18:00:06

标签: 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.", e);
        }
        /* Attempts to load configuration */
        conf = loadConfiguration(); //this may throw some subclasses of RuntimeException
    }

因为我希望JDBC驱动程序和配置只加载一次。

我想在创业时做这样的事情(我会尽可能地简化):

public static void main(String[] args) {
    try {
        // load the class that contains the code above
    } catch (DBConfigurationException e) {
        // display proper error message using JOptionPane, then quit
    } catch (MissingConfigurationException e) {
        // display proper error message using JOptionPane
        // show a JDialog and allow user to input and store a configuration
    } catch (InvalidConfigurationException e) {
        // display proper error message using JOptionPane
        // show a JDialog and allow user to input and store a configuration
    }

    /* if everything it's ok */
    // do some other checks in order to decide which JFrame display first.
}

现在,问题是如果发生异常,JVM将抛出广告ExceptionInInitializerError并且不会构造对象。 可能我仍然可以理解出了什么问题,抓住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();
    }
}

但即使这个对我来说听起来也不正确:只有在第一次使用时才会抛出异常(我知道它会在启动时因为我必须进行检查),加载类时是。所以从理论上讲,第一种方式更为正确。 :\

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

问题是具有静态初始化程序 NEEDS 的类都包含驱动程序和配置,因此在它们都可用之前不应该。 :\

2 个答案:

答案 0 :(得分:3)

为什么不在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
}

答案 1 :(得分:0)

您可以使用Singleton类。 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;
    }
}