为循环中的第一次迭代编程不同的行为
programming different behaviour for first iteration in loop
我有一个需要迭代的对象集合。该集合的大小可变。如果集合中的对象超过1个,我需要对对象进行特殊处理 2 .. infinity.
执行此操作的首选方法是什么?例如:
int count = 1;
for (CustomObject co : CustomObjectCollection) {
methodAll(co);
if(count > 1) {
methodSpecial(co);
}
count = count++;
}
除了一个错误外,您拥有的一切都可以使用:count = count++
完全没有任何作用。 count = count + 1
可以工作,或者 count++
,但是 count = count++
是一个空操作。
如果您不需要特别跟踪计数,您也可以只使用布尔标志。
boolean first = true;
for (CustomObject co : CustomObjectCollection) {
methodAll(co);
if (!first) {
methodSpecial(co);
}
first = false;
}
使用哪个
使用哪个取决于您的具体用例。假设您不打算优化每秒最后一次操作的性能,那么 选择声明您的意图的选项:
如果您想在循环外跟踪或使用计数,count++
很好(根据 Louis 的回答,它是 count++
,而不是 count = count++
)
如果集合支持 get(i)
操作,for(int i = 0; i < collection.size(); i++)
也很好。这还允许您通过将 int i
初始化为不同的索引来跳过第一项。如果您不希望额外的计数变量在循环外徘徊,则可以使用它。
- 上面的
boolean first = true;
(或相反的 boolean notFirst = false;
)突出显示您想要区别对待第一个和后续元素
- 如果您的集合上有 List 界面并且想跳过一定数量的元素,那么
subList
是一个不错的选择
性能
如果性能是一个问题,那么针对您的平台和实施进行衡量,但根据一般经验,从最慢到最快,第一个和最后一个之间的差异 <=20x :
- 对于带有迭代器的每个循环:最慢
for(int i = 0; i < list.size() ; i++)
- 声明
int size = list.size()
然后 for(int i = 0; i < size; i++)
循环
然而,这些速度结果取决于很多因素,除非性能是设计目标或确定的问题,否则迭代器会一直使用,直到您有理由使用其他两个中的一个 - 迭代器通常足够快。
我认为更好的方法是像这样直接使用迭代器:
Iterator<CustomObject> it = customObjectCollection.iterator();
if(it.hasNext()) { //first pass don't call methodSpecial
methodAll(it.next());
}
CustomObject customObj;
while(it.hasNext()) { //all the rest 2..infinity
customObj = it.next();
methodAll(customObj);
methodSpecial(customObj);
}
customObj = null; // for garbage collection
这样您就不必检查每次迭代是否是第一次 运行。
这将适用于任何 Iterable
(无论如何,foreach
循环已经需要它)。
注意:如果这不是有序集合,您可能会在第一次迭代中得到不同的元素,然后您可能会期望。
我有一个需要迭代的对象集合。该集合的大小可变。如果集合中的对象超过1个,我需要对对象进行特殊处理 2 .. infinity.
执行此操作的首选方法是什么?例如:
int count = 1;
for (CustomObject co : CustomObjectCollection) {
methodAll(co);
if(count > 1) {
methodSpecial(co);
}
count = count++;
}
除了一个错误外,您拥有的一切都可以使用:count = count++
完全没有任何作用。 count = count + 1
可以工作,或者 count++
,但是 count = count++
是一个空操作。
如果您不需要特别跟踪计数,您也可以只使用布尔标志。
boolean first = true;
for (CustomObject co : CustomObjectCollection) {
methodAll(co);
if (!first) {
methodSpecial(co);
}
first = false;
}
使用哪个
使用哪个取决于您的具体用例。假设您不打算优化每秒最后一次操作的性能,那么 选择声明您的意图的选项:
-
如果您想在循环外跟踪或使用计数,
count++
很好(根据 Louis 的回答,它是count++
,而不是count = count++
)
如果集合支持 for(int i = 0; i < collection.size(); i++)
也很好。这还允许您通过将int i
初始化为不同的索引来跳过第一项。如果您不希望额外的计数变量在循环外徘徊,则可以使用它。- 上面的
boolean first = true;
(或相反的boolean notFirst = false;
)突出显示您想要区别对待第一个和后续元素 - 如果您的集合上有 List 界面并且想跳过一定数量的元素,那么
subList
是一个不错的选择
get(i)
操作,性能
如果性能是一个问题,那么针对您的平台和实施进行衡量,但根据一般经验,从最慢到最快,第一个和最后一个之间的差异 <=20x :
- 对于带有迭代器的每个循环:最慢
for(int i = 0; i < list.size() ; i++)
- 声明
int size = list.size()
然后for(int i = 0; i < size; i++)
循环
然而,这些速度结果取决于很多因素,除非性能是设计目标或确定的问题,否则迭代器会一直使用,直到您有理由使用其他两个中的一个 - 迭代器通常足够快。
我认为更好的方法是像这样直接使用迭代器:
Iterator<CustomObject> it = customObjectCollection.iterator();
if(it.hasNext()) { //first pass don't call methodSpecial
methodAll(it.next());
}
CustomObject customObj;
while(it.hasNext()) { //all the rest 2..infinity
customObj = it.next();
methodAll(customObj);
methodSpecial(customObj);
}
customObj = null; // for garbage collection
这样您就不必检查每次迭代是否是第一次 运行。
这将适用于任何 Iterable
(无论如何,foreach
循环已经需要它)。
注意:如果这不是有序集合,您可能会在第一次迭代中得到不同的元素,然后您可能会期望。