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

我一直在努力解决Java中的一个问题并开始找到我,我无法想到一个合适的方法来解决它。

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

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

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

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

有任何想法吗…?

怎么样

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

 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可能是一个坏主意。 它会破坏你的unit testing。

再想一想,我想我刚刚提出了一个解决方案! – 使用中间变量。

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

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

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

与OP的问题一样,我必须能够找到一种方法,将值分配给要从文件系统上的.properties文件读入的最终字段,因此我的应用程序无法知道这些值。发生了。 使用通用方法调用将.properties文件的内容读取到应用程序启动时的Properties对象后分配值是一个Hail Mary传递,幸好得到了解决。 它也限制了没有。 每次应用程序加载到内存中时,只需通过代码检查以查看Properties对象当前是否为null,就必须将文件读取一次。 但是,当然,一旦被分配,最终字段的值不能被改变,除非通过在运行时操作字段的修改定义来改变其“最终”状态(如在SO上的某些其他地方所讨论的,例如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); } } 

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