2012-09-06 57 views
2

我写了下面的代码:如何捕捉异常在静态初始化块抛出

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司机和配置,所以它不应来之前他们两人都可以使用。 :\

+0

根据定义,从'static {}'块抛出的异常生成ExceptionInInitializer并将类标记为不可用。这是它应该的方式(加上或减去一个小的三角洲)。 –

回答

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 
} 
+0

“欺骗”一词。 ;)另外,静态初始值设定项应该或多或少的避免,因为如果它们失败,你可以得到奇怪的错误,比如'NoClassDefFound'错误。 – Brian

+1

好吧,从不需要欺骗的角度来看,这很好,但它并没有以模块化方式隔离需求。取决于应用程序的大小和你正在写的东西,我想。 –

+1

@TonyK。这取决于应用程序。如果它需要数据库访问来运行,它应该在'main'线程中失败并终止。如果没有,那么它应该在其他地方失败,我同意。 – Brian

0

您可以使用Singleton类。例如

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; 
    } 
} 
+0

这只会将问题移动到getConf(),它仍然可以在第一次调用时抛出异常;顺便说一句,我应该如何使用它?如果我没有弄错,“private static final Configuration conf = DBConfigProvider.getConf()”这行仍然会抛出ExceptionInInitializerError。 – tmh

+0

为什么你需要配置静态变量?我期待您在实际需要时调用DBConfigProvider.getConf()。使这个单例成为背后的想法是,你保持一个单一的配置实例,同时“迟到”(当需要时)初始化它。 – Sameer

+0

由于负责连接数据库的类,它应该保存必要的细节(驱动程序和配置),并且能够在不根据自己的用法做出假设的情况下工作(例如,在调用方法getConnection()之前加载驱动程序和设置配置)。 其他类应调用其方法不知道这些细节。 (抱歉英语不好,我今天感觉诵读困难:D) – tmh

相关问题