在Java中初始化最终变量的问题

时间:2010-05-05 13:51:20

标签: java exception constants final

我在Java中遇到了一个问题的细微变化,它开始转向我,我真的想不出一个正确的解决方法。

我有一个最终的对象属性,但是是动态的。也就是说,我希望值在指定后保持不变,但每个运行时的值可以不同。所以我在课程开头声明了类级变量 - 比如private final FILE_NAME;。然后,在构造函数中,我为其赋值 - 比如FILE_NAME = buildFileName();

当我在引发异常的buildFileName()方法中有代码时,问题就开始了。所以我在构造函数中尝试这样的东西:

try{
   FILE_NAME = buildFileName();
}
catch(Exception e){
   ...
   System.exit(1);
}

现在我有一个错误 - “空白的最终字段FILE_NAME可能尚未初始化。”这是我开始对Java的严格编译器感到有些恼火的地方。我知道这不会是一个问题,因为如果它到达catch,程序将退出...但编译器不知道,因此不允许此代码。如果我尝试在catch中添加一个虚拟赋值,我会得到 - “可能已经分配了最终字段FILE_NAME。”我显然不能在try-catch之前分配一个默认值,因为我只能分配一次。

任何想法......?

5 个答案:

答案 0 :(得分:20)

怎么样

String tempName = null;
try{
   tempName = buildFileName();
}
catch(Exception e){
   ...
   System.exit(1);
}
FILE_NAME = tempName;

答案 1 :(得分:7)

要么

try {
   FILE_NAME = buildFileName();
} catch (Exception e){
   ...
   System.exit(1);
   throw new Error();
}

或者有些人更喜欢:

private static final String FILE_NAME = fileName();

private static String fileName() {
    try {
        return buildFileName();
    } catch (Exception e){
        ...
        System.exit(1);
        throw new Error();
    }
}

但是在静态初始化程序中调用System.exit可能是一个坏主意。它会破坏你的单元测试。

答案 2 :(得分:4)

第二个想法,我想我想出了一个解决方案! - 使用中间变量。

String fileName = null;
try{
   fileName = buildFileName();
}
catch(Exception e){
   ...
   System.exit(1);
}
FILE_NAME = fileName;

不知道为什么我这么久才想到这个...

答案 3 :(得分:1)

我个人只会抛出一个错误 - 如果你的错误流程设计得当,System.exit()应该是多余的。如果抛出错误,你的程序可能不会闯入荒野......?

答案 4 :(得分:0)

与OP的问题一样,我必须能够找到一种方法,将值分配给要从文件系统上的.properties文件读入的最终字段,因此值不能超过&#39 ;直到发生这种情况,我的应用程序才知道。使用通用方法调用将.properties文件的内容读取到应用程序启动时的Properties对象后分配值是一个Hail Mary传递,谢天谢地。它也限制了没有。每次应用程序加载到内存中时,只需通过代码检查以查看Properties对象当前是否为null,就必须将文件读取一次。但是,当然,一旦被分配,最终字段的值不能改变,除非通过改变它的" final"状态通过操作字段在运行时修改定义(正如在其他地方所讨论的那样,如https://stackoverflow.com/a/3301720/1216686 - 偷偷摸摸,但我喜欢它!)。代码示例,为简洁起见,省略了NPE的典型运行时错误检查:

import java.util.Properties;

public class MyConstants {

  private static Properties props; // declared, not initialized,
                                   // so it can still be set to
                                   // an object reference.

  public static String MY_STRING = getProperty("prop1name", "defaultval1");
  public static int MY_INT = Integer.parseInt(getProperty("prop2name", "1"));
  // more fields...

  private static String getProperty(String name, String dflt) {
   if ( props == null ) {
     readProperties();
   }
   return props.getProperty(name, dflt);
  } 

  private static void readProperties() {
     props = new Properties(); // Use your fave way to read
                      // props from the file system; a permutation
                      // of Properties.load(...) worked for me.
  } 

  // Testing...
  public static void main(String[] args) {
      System.out.println(MY_STRING);
      System.out.println(MY_INT);
  }

}

这使您可以外部化要读入应用程序的属性,并仍然将用于保存其值的字段标记为" final"。它还允许您保证最终字段值的返回值,因为Properties类中的getProperty()允许方法的调用代码传递默认值,以便在属性的键值使用时使用在外部.properties文件中找不到对。