在第二种方法中使用第一种方法是否有任何内存/性能优势?
第一
public List<Integer> getList1(List<Integer> data) {
List<Integer> list = new ArrayList<Integer>();
for (Integer element: data) {
if (element % 2 == 0) {
list.add(element);
}
}
return list.isEmpty() ? Collections.<Integer>emptyList() : list;
}
第二
public List<Integer> getList2(List<Integer> data) {
List<Integer> list = new ArrayList<Integer>();
for (Integer element: data) {
if (element % 2 == 0) {
list.add(element);
}
}
return list;
}
答案 0 :(得分:7)
任何重要的程度取决于调用getList1
的频率,当然它会返回一个空列表。但是:
Collections#emptyList
的JavaDoc提供了见解:
实施说明:此方法的实现无需为每次调用创建单独的List对象。使用此方法可能具有与使用同名字段相当的成本。 (与此方法不同,该字段不提供类型安全性。)
所以是的,如果你使用emptyList
而不是每次返回一个新的空列表,你(可能)最终会减少内存中的对象,因为Collections#emptyList
可以自由地返回 List<Integer>
每次调用它(因为它是不可变的)。
您 可能 也会获得不相关的性能提升(至少使用Oracle的JVM)。在某些情况下,我根本不了解细节,但在某些情况下,Oracle的JVM最初可以在堆栈上分配分配给局部变量的对象,只有在传输它们时才会将它们传输到堆中。对它们的引用在函数调用终止后仍然存在。基于堆栈的分配确实快,当然不会受到碎片的影响。因此,在空列表方案中,您不仅可以避免使用空列表混乱内存,还可以获得速度优势(JVM不必将您在堆栈中创建的空列表复制到堆中)。但同样,我不知道JVM优化是否必然适用于您的代码。
如果内存优化真的对你的代码很重要,你不想依赖堆栈分配的东西,只需要轻微牺牲代码清晰度和 tiny 运行时成本,如果您不需要,可以避免分配列表:
public List<Integer> getList1(List<Integer> data) {
List<Integer> list = null;
for (Integer element: data) {
if (element % 2 == 0) {
if (list == null ) {
list = new ArrayList<Integer>();
}
list.add(element);
}
}
return list == null ? Collections.<Integer>emptyList() : list;
}
但请注意,存在重要的语义差异。在您的第一个代码块中,getList1
不一致:它可能返回调用代码可以修改的列表(如果它不为空),或者它可能返回一个不可变列表(如果它是空的)。 getList1
应该总是返回一个可变列表或不可变列表,有时候不会返回一个列表,有时会返回另一个列表。如果它可以是不可变的,你应该使用Collections#unmodifiableList
来获取非空列表的不可变版本,并返回它。
答案 1 :(得分:0)
既然你要回归list
,为什么会这样?这只是多余的。
首选第二种方式。
另外,请参阅emptyList()
方法文档
实施说明:此方法的实现无需为每次调用创建单独的List对象。使用此方法可能具有与使用同名字段相当的成本。 (与此方法不同,该字段不提供类型安全性。)
答案 2 :(得分:0)
有一个微妙的区别。
如果getList1
返回空列表,则该列表不可变:
List<Integer> l1 = getList1();
assertTrue(l1.isEmpty());
l1.add(1); //exception
List<Integer> l2 = getList2();
assertTrue(l2.isEmpty());
l2.add(1); //OK
此外:
List<Integer> l1a = getList1();
List<Integer> l1b = getList1();
assertTrue(l1a.isEmpty());
assertTrue(l1b.isEmpty());
assertSame(l1a, l1b); //same reference so there is some saving in memory
List<Integer> l2a = getList2();
List<Integer> l2b = getList2();
assertTrue(l2a.isEmpty());
assertTrue(l2b.isEmpty());
assertNotSame(l2a, l2b); //not same reference, two unique lists
这两者是相互关联的,如果它不是不可变的,那么共享引用将不起作用。