哪一种是迭代特定集合的元素的最佳方式



在遍历特定集合的元素时,我总是对每个循环使用

只是为了检查每个循环过程消耗了多少时间,我这样编码,

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很常见,那是因为它更容易理解、维护和优化,而现在已经确定不需要了。

最新更新