在Java

时间:2016-06-30 13:42:35

标签: java arraylist initialization

在Java中初始化ArrayList字段的最佳做法是什么(以避免测试空值)?

在声明中,像这样:

private List<String> myList = new ArrayList<String>();

或者在吸气器中,像这样:

public List<String> getMyList() {
    if(myList == null) {
        myList = new ArrayList<String>();
    }
    return myList;
}

或者,在构造函数中:

public Test(){
    myList = new ArrayList<String>();
}

也许它是一样的,但我很想知道。

3 个答案:

答案 0 :(得分:8)

第一个选项允许你做

private final List<String> myList = new ArrayList<>();

这样可以防止您以后意外地创建一个全新的列表;从而帮助(很多,而不是所有)多线程问题。除此之外,现在编译器可以帮助您确保您的字段初始化完全一次

除此之外,第二个选项可以看作&#34;延迟初始化&#34;。从这个意义上说:它可以被视为&#34;优化选择&#34;!从那里:许多人主张避免过早优化!

你知道,当你不能依赖已经创建的列表时会造成很多麻烦。因此,即使从这个角度来看,你还有另一个论点,更喜欢选项1!

编辑,关于编译器选项:从语义上看,选项1和3是(或多或少)&#34;等于&#34; [提示:如果你发现如果选择option1或option3,它会对你的代码产生影响......这将很好地表明你在代码中做了一些非常错误的事情)。

尽管如此,有一点可以产生影响 - 如果你有一个&#34;依赖注入&#34;构造函数,如:

public YourClass() { this(new ArrayList<String>); }
YourClass(List<String> incomingList) { myList = incomingList; }

此解决方案适用于您需要的那些类型的对象&#34;控制&#34 ;;在以下意义上:您需要将模拟传递给您的类以启用单元测试。

长话短说:

  • 如果可能,请选择option1:使用最终
  • 如果需要依赖注入,请使用option3
  • 避免使用option2,除非你有充分的理由去寻找它

答案 1 :(得分:1)

一般来说,getter中的延迟初始化比它的价值更麻烦。如果你有一个严重的问题,你想要最小化列表使用的内存(因为你希望它在大多数情况下是空的),你可以初始化它初始容量为零:

private List<String> myList = new ArrayList<String>(0);

除了易读性之外,在实例变量声明和构造函数中初始化之间没有实际区别。如果将初始化放在实例声明上,使用构造函数将构造函数中的初始化与实例变量相匹配,以确保它们被覆盖,则更容易确保所有内容都已初始化。 / p>

许多现实世界的代码必须与第三方库和框架一起使用。当你创建一个必须使用像Hibernate或Spring这样的库或框架的类时,getter中的延迟初始化是不可能的,因为Spring接管了这些东西,或者因为使用你的类的库交换出来你的List实现由于各种原因(Hibernate将这样做来实现延迟加载)。因此,尽可能使您的getter和setter尽可能简单直接,以免他们使用第三方代码所做的假设无效。

答案 2 :(得分:0)

这取决于使用情况,但我更喜欢第一种选择。

private List<String> myList = new ArrayList<String>();

如果类的用户能够将myList变量设置为null,则期望您的类重新创建ArrayList,第二个选项可能会有一些好处。这对我来说似乎是不好的做法。