什么时候使用空白的最终变量?

我正在查看关于最终变量的另一个问题 ,并注意到你可以声明最终变量而不初始化它们(一个空白的最终变量)。 有没有理由这样做,什么时候有利?

这对于创建不可变对象很有用:

 public class Bla { private final Color color; public Bla(Color c) {this.color = c}; } 

Bla是不可变的(一旦创建,它就不能改变,因为颜色是最终的)。 但是你仍然可以通过用各种颜色构建它们来创建各种Blas。

另请参阅此问题 。

编辑

也许值得补充的是,“空白决赛”在Java中具有非常特殊的含义,这似乎在评论中引起了一些混淆 – 参见Java语言规范4.12.4 :

空白最终是一个最终变量,其声明缺少初始化程序。

然后,您必须在构造函数中分配该空白最终变量。

类的final属性必须在创建对象之前指定一个值。 因此,您可以为其赋值的最后一点是构造函数。

这通常用于不可变对象 。

  public class Foo { private final Bar bar; public Foo(Bar bar) { this.bar = bar; } public Bar getBar() { return new Bar(bar); } } 

维基说了些什么

防御性复制。

当你不知道在Object的检测之前它的值是什么时,你可以这样做,它只需要在它的构造函数中赋值。

这是您创建不可变对象的方式 ,它在构建器模式中使用。

 class Builder{ final BuilderContext context; private Builder(BuilderContext context){ this.context=context; } public static Builder New(){ return new Builder(new BuilderContext()); } 

必须在构造函数中的“某处”指定空白的最终变量。 一个相当构造的例子:

 public class Test { final int sign; public Test(String upDown) { if (upDown.equals("up")) { sign = +1; } else { sign = -1; } } } 

有一种情况可能是你有一个你想要声明final的字段,但是它的赋值可能抛出exception而你希望能够在发生这种情况时采取行动:

 class A { final URLConnection conn; A(String url) { try { this.conn = new URL(url).openConnection(); } catch (IOException | MalformedURLException e) { // Maybe this isn't fatal, so just handle the Exception // here and move on happily } } } 

在方法中使用空白的最终变量来显示使用该变量的所有代码路径只分配该变量一次(或抛出exception)。 Java编译器将保证在使用之前分配空白的最终变量。

某些方法中的示例代码:

  final Foo foo; if (condition1()) { foo = makeFoo(1); } else if (condition2()) { throw new BarException(); } else { foo = makeFoo(-1); } ... blahBlahBlah(foo); 

使用空白的最终变量告诉下一个读者代码,编译器在调用blahBlahBlah(foo)之前保证有人指定了foo。

这个问题询问“空白的最终变量 ”。 讨论“空白的最终领域 ”是一个不同的讨论,并且本身很有趣。

来自维基百科

在Java 1.1中引入的空白final是一个最终变量,其声明缺少初始化器。 空白最终版只能分配一次,并且必须在分配发生时取消分配。 为了做到这一点,Java编译器运行流分析以确保对于空白最终变量的每个赋值,在赋值之前肯定未赋值变量; 否则会发生编译时错误。

通常,Java编译器将确保在为其分配值之前不使用空白final,并且一旦分配了值,则现在的final变量不能重新分配另一个值。

注意到你可以在不初始化它们的情况下声明final变量

您必须稍后将其初始化(例如在构造函数中),以便它不会保持为空。

我发现它们对于导出状态的方法非常有用。 它提供了一个干净的执行路径,并确保状态变量只分配一次。 例如:

 public boolean isEdible() { final boolean edible; if (vegetable) { edible = true; } else if (animal) { if (vegetarian) { edible = false; } else { edible = true; } } System.out.println("Is edible: " + edible); return edible; }