在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>();
}
也许它是一样的,但我很想知道。
答案 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 ;;在以下意义上:您需要将模拟传递给您的类以启用单元测试。
长话短说:
答案 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,第二个选项可能会有一些好处。这对我来说似乎是不好的做法。