在遍历特定集合的元素时,我总是对每个循环使用。
只是为了检查每个循环过程消耗了多少时间,我这样编码,
public class LoopingDemo {
static ArrayList<String> arrayList = new ArrayList<String>();
static double start;
static double end;
public static void iterator() {
simpleForLoop();
System.out.println();
forEachLoop();
System.out.println();
useWhileLoop(arrayList);
System.out.println();
useForLoop(arrayList);
System.out.println();
enumerator();
}
public static void simpleForLoop(){
start = System.nanoTime();
for(int i=0;i<arrayList.size();i++){
String str = arrayList.get(i);
System.out.println(": "+str);
}
end = System.nanoTime();
System.out.println("Taken taken in simpleForLoop process: "
+ (end - start));
}
public static void forEachLoop() {
start = System.nanoTime();
for (String str : arrayList) {
System.out.println(str);
}
end = System.nanoTime();
System.out.println("Taken taken in forEachLoop process: "
+ (end - start));
}
public static void enumerator() {
start = System.nanoTime();
// get the Enumeration object
Enumeration<String> en = Collections.enumeration(arrayList);
// enumerate through the ArrayList elements
System.out.println("Enumerating through Java ArrayList");
while (en.hasMoreElements()) {
System.out.println(en.nextElement());
/*
* String name = (String) en.nextElement();
* System.out.println(name);
*/
}
end = System.nanoTime();
System.out.println("Taken taken in enumeration process: "
+ (end - start));
}
private static void useWhileLoop(Collection<String> myList) {
start = System.nanoTime();
Iterator<String> itr = myList.iterator();
while (itr.hasNext()) {
String str = itr.next(); // Returns the next element in the
// iteration.
System.out.println(str);
// System.out.println(itr.next()); // in one line
}
end = System.nanoTime();
System.out.println("Taken taken in useWhileLoop process: "
+ (end - start));
}
/**
* Note that this for-loop does not use an integer index.
*/
private static void useForLoop(Collection<String> myList) {
start = System.nanoTime();
for (Iterator<String> itr = myList.iterator(); itr.hasNext();) {
System.out.println(itr.next());
}
end = System.nanoTime();
System.out.println("Taken taken in useForLoopWithIterator process: "
+ (end - start));
}
public static void addElements() {
// Add elements to the array list.
arrayList.add("C");
arrayList.add("A");
arrayList.add("E");
arrayList.add("B");
arrayList.add("D");
arrayList.add("F");
arrayList.add(1, "A2");
}
public static void main(String[] args) {
addElements();
iterator();
}
}
令人惊讶的是,对于每个循环,通过完成的循环过程只落后于对于循环的简单。(不同配置的不同机器的结果可能不同。)
控制台输出:
Taken taken in simpleForLoop process: 853200.0
Taken taken in forEachLoop process: 788993.0
Taken taken in useWhileLoop process: 452014.0
Taken taken in useForLoopWithIterator process: 299775.0
Taken taken in enumeration process: 766756.0
那么,为什么人们更喜欢通过为每个循环来执行呢?是否有基于性能的原因?
IIRC,对于每个循环来说,它只是一个语法糖,在遍历集合时,它将被编译为具有迭代器的for循环。在运行时不应该存在性能差异。
您看到的差异是编写不好的基准测试逻辑的典型结果。如果将"for循环with迭代器"作为第一个要调用的方法,您会发现它运行缓慢。
更不用说每次测试的持续时间太短而不重要,在我添加了一些热身之后(先运行所有测试5次,然后查看第6个结果的结果),结果变得正常:
Taken taken in useForLoopWithIterator process: 105110.0
Taken taken in simpleForLoop process: 122181.0
Taken taken in useWhileLoop process: 104774.0
Taken taken in enumeration process: 123520.0
Taken taken in forEachLoop process: 106782.0
forEachloop、useForLoopWithIterator和useWhileLoop的结果几乎相同(它们应该是相同的)。在遍历集合时,基于索引的访问几乎是最不可取的。虽然这里的差异并不显著,但如果您使用的是非基于数组的集合,例如LinkedList,则会看到更大的差异。
我使用它是为了方便。您不需要考虑带有"for(Typee:set).
只要代码足够快,我就会追求简单性/可维护性。只有当性能成为一个问题时,我才会考虑优化。即便如此,工作流中的某些部分在优化时可能会产生更大的性能提升。
《高效Java》一书涵盖了这一点。基本上,foreach简洁而优雅,任何人都可以阅读和理解代码。人们总是说永远不要过早地优化。只有当你绝对确定需要优化时,才考虑优化。因此,如果你发现foreach很常见,那是因为它更容易理解、维护和优化,而现在已经确定不需要了。