实例初始化程序是否被视为不良样式

时间:2011-01-13 00:08:04

标签: java

我个人非常喜欢实例初始化器 - 我使用它们来为诸如集合之类的东西分配默认值,因此在编写构造函数时,我不必记住每次都为它们分配相同的默认值。对我来说这似乎很优雅 - 避免恼人的NPE弹出并避免重复代码。私有方法似乎不太好,因为a)它不能为最终字段赋值,b)它可以在代码中的其他地方运行,c)在每个构造函数的开头仍然需要显式调用该方法。 / p>

然而,与我所说过的其他人的另一面是,他们感到困惑,有些人阅读代码可能无法理解他们做什么或何时被调用,因此他们可能会导致比他们解决的问题更多的问题。 / p>

是否应该鼓励或避免使用这些初始化程序?或者它是“每个人都有自己的”案例?

5 个答案:

答案 0 :(得分:3)

具体取决于您的代码中Java读者的知识水平,以及替代方案是否切实可行。

替代方案是:

  • 内联到每个构造函数中。如果有几个构造函数,则会违反DRY。
  • 将所有构造函数委托给相同的构造函数,并将代码放在该构造函数中。如果构造函数是非平凡的,并且采用不同的参数,则可能需要编写一个新的构造函数,该构造函数接收其参数中所有字段的值。如果有很多字段,这可能会变得相当冗长(并且难以阅读,因为将哪个值分配给哪个字段并不明显)
  • 让所有构造函数调用init方法。无法以这种方式分配最终字段。应该可能会阻止该方法被覆盖。可能希望防止它被多次调用。

由于初始化程序并不常见,因此只有在使用它们有明显优势时才应该使用它们。我最近使用的是:

private final Collator collator = Collator.getInstance();
{
    collator.setStrength(Collator.SECONDARY);
}

在一个具有几个构造函数的类中,这些构造函数具有相当不同的参数列表和六个其他字段。

答案 1 :(得分:1)

我并没有真正使用它们,但是我可以看到它们有用的一种情况是当你有多个构造函数,而不是自己调用(this(..))时,需要共享一些常见的初始化逻辑,而不需要创建一个特定的私人方法。 哦,我使用实例初始化器的唯一地方就是在一行地图中快速初始化,例如:

Map<String,String> m = new HashMap<String,String>(){{
   put("a","b");
   put("c","b");
   put("d","b");
}};

在让我们说一个接口

中初始化一个地图会很有用
interface  A {

   Map<String,String> PROPS = Collections.unmodifiableMap(new HashMap<String,String>(){{
      put("a","b");
      put("c","b");
      put("d","b");
   }});
}

仍然这样做你最终得到了一个HashMap的匿名子类...

答案 2 :(得分:1)

最好重载构造函数并拥有任意数量的构造函数变体。最好的例子是Java的Arraylist。它有两个构造函数。一个以整数作为参数,另一个是默认构造函数。如果你看一下默认的构造函数,它就会使用常量值10来调用Single参数构造函数。

List<Object> x = new ArrayList<Object>(); //Creates with default capacity 10
List<Object> y = new ArrayList<Object>(40); //Creates with the specified capacity 40

答案 3 :(得分:1)

我会留下他们的首选。但基于其他反应,它似乎可能更“自己”。我喜欢它们因为它将相关信息保存在一起。

可以在一个地方完成所有操作,而不是在构造函数中声明值并设置它

答案 4 :(得分:0)

您可以使用带参数的构造函数,此构造函数调用私有setter。而不是实现一个默认构造函数,该构造函数使用默认值调用该构造函数。如果要为属性指定默认值,请在声明中执行。

实例和静态初始化器适用于初始化复杂的数据结构,如矩阵或多维数据集。

顺便说一下,最终属性大多称为常量。