为循环中的第一次迭代编程不同的行为

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;
}

使用哪个

使用哪个取决于您的具体用例。假设您不打算优化每秒最后一次操作的性能,那么 选择声明您的意图的选项:

    如果您想在循环外跟踪或使用计数,
  1. count++ 很好(根据 Louis 的回答,它是 count++,而不是 count = count++
  2. 如果集合支持 get(i) 操作,
  3. for(int i = 0; i < collection.size(); i++) 也很好。这还允许您通过将 int i 初始化为不同的索引来跳过第一项。如果您不希望额外的计数变量在循环外徘徊,则可以使用它。
  4. 上面的 boolean first = true;(或相反的 boolean notFirst = false;)突出显示您想要区别对待第一个和后续元素
  5. 如果您的集合上有 List 界面并且想跳过一定数量的元素,那么 subList 是一个不错的选择

性能

如果性能是一个问题,那么针对您的平台和实施进行衡量,但根据一般经验,从最慢到最快,第一个和最后一个之间的差异 <=20x :

  1. 对于带有迭代器的每个循环:最慢
  2. for(int i = 0; i < list.size() ; i++)
  3. 声明 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 循环已经需要它)。

注意:如果这不是有序集合,您可能会在第一次迭代中得到不同的元素,然后您可能会期望。