在 Java 中初始化最终变量时出现问题

发布于 2024-08-31 02:15:05 字数 667 浏览 6 评论 0原文

我不断地遇到 Java 中的一个问题的细微变化,它开始困扰着我,而且我真的想不出一个合适的方法来解决它。

我有一个最终但动态的对象属性。也就是说,我希望该值在分配后保持不变,但每个运行时该值可以不同。因此,我在类的开头声明类级别变量 - 例如 private Final FILE_NAME;。然后,在构造函数中,我为其分配一个值 - 比如说 FILE_NAME = buildFileName();

当我在 buildFileName() 方法中包含引发异常的代码时,问题就开始了。所以我在构造函数中尝试类似的操作:

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

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

有什么想法吗...?

I keep running into slight variations of a problem in Java and it's starting to get to me, and I can't really think of a proper way to get around it.

I have an object property that is final, but dynamic. That is, I want the value to be constant once assigned, but the value can be different each runtime. So I declare the class level variable at the beginning of the class - say private final FILE_NAME;. Then, in the constructor, I assign it a value - say FILE_NAME = buildFileName();

The problem begins when I have code in the buildFileName() method that throws an exception. So I try something like this in the constructor:

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

Now I have an error - "The blank final field FILE_NAME may not have been initialized." This is where I start to get slightly annoyed at Java's strict compiler. I know that this won't be a problem because if it gets to the catch the program will exit... But the compiler doesn't know that and so doesn't allow this code. If I try to add a dummy assignment to the catch, I get - "The final field FILE_NAME may already have been assigned." I clearly can't assign a default value before the try-catch because I can only assign to it once.

Any ideas...?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

谁对谁错谁最难过 2024-09-07 02:15:05

怎么样

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

How about

String tempName = null;
try{
   tempName = buildFileName();
}
catch(Exception e){
   ...
   System.exit(1);
}
FILE_NAME = tempName;
べ繥欢鉨o。 2024-09-07 02:15:05

要么

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 可能是一个坏主意。它会让你的单元测试变得混乱。

Either

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

Or some prefer:

private static final String FILE_NAME = fileName();

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

But calling System.exit in a static initialiser is probably a bad idea. It's going to mess your unit tests up.

有深☉意 2024-09-07 02:15:05

转念一想,我想我刚刚想出了一个解决方案! - 使用中间变量。

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

不知道为什么我花了这么长时间才想到这个......

On second thought, I think I just came up with a solution! - use an intermediate variable.

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

Don't know why it took me so long to think of this...

与往事干杯 2024-09-07 02:15:05

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

I would personally just throw an Error -- if your error flow is properly designed, the System.exit() should be redundant. Your program presumably doesn't plough on into the wilderness if an Error is thrown...?

你又不是我 2024-09-07 02:15:05

与OP的问题一样,我必须能够找到一种方法将值分配给要从文件系统上的.properties文件读取的最终字段,因此我的应用程序在此之前无法知道这些值发生了。在应用程序启动时将 .properties 文件的内容读取到 Properties 对象后,使用通用方法调用来分配值是一个万福玛丽通行证,值得庆幸的是。它还限制了数量。每次应用程序加载到内存中时,只需通过代码检查 Properties 对象当前是否为空,就必须读取一次文件。但是,当然,一旦分配,最终字段的值就不能更改,除非通过在运行时操纵字段的修改定义来更改其“最终”状态(如 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 文件。

Along the same lines as the OP's issue, I had to be able to find a way to assign values to final fields to be read in from a .properties file on the filesystem, so the values couldn't be known by my app until that happened. Using a generalized method call to assign the value after reading the content of the .properties file into a Properties object on app startup was a Hail Mary pass that thankfully worked out. It also limits the no. of times the file has to be read to once per the app's getting loaded into the memory simply by the code checking to see if the Properties object is or is not currently null. But of course, once assigned, the final field's value cannot be altered except by altering its "final" status via manuipulating the field's modifying definition at runtime (as discussed in some other places here on SO, such as https://stackoverflow.com/a/3301720/1216686 - sneaky, but I love it!). Code example, with typical runtime error checking such as for NPEs omitted for brevity:

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);
  }

}

This lets you externalize properties to be read into the app and still mark the fields used to hold their values as "final". It also allows you to guarantee a returned value for the final field value since getProperty() in the Properties class allows the method's calling code to pass in a default value to use in case the property's key-value pair wasn't found in the external .properties file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文