• Tags         
  • 2018-08-02  08:37:44        
  • 72 °C    

    Java中的Iterator和Foreach的背景

    Iterator是集合框架提供的接口,用于遍历集合以及集合中项目的顺序访问。

       // Iterating over collection 'c' using terator
       for (Iterator i = c.iterator(); i.hasNext(); ) 
           System.out.println(i.next());

     

    Foreach循环,用于遍历集合中的项目。

       // Iterating over collection 'c' using for-each 
       for (Element e: c)
           System.out.println(e);

    我们将for-each循环中使用的':'读作“in”。因此循环读取为“对于元素中的每个元素e”,这里元素是存储元素类型项的集合。

    注意:在使用lambda表达式的Java 8中,我们可以简单地用for替换for-each循环

    elements.forEach(e  - > System.out.println(e));

     

    Java中的Iterator和Foreach两次遍历之间的差异

    在for-each循环中,我们不能修改集合,另一方面它会抛出一个ConcurrentModificationException,迭代器我们可以修改集合。

    修改集合只是意味着删除元素或更改集合中存储的项目的内容。发生这种情况是因为for-each循环隐式地创建了一个迭代器,但它没有向用户公开,因此我们无法修改集合中的项目。

    什么时候使用哪个遍历?

    • 如果我们必须修改集合,我们可以使用Iterator。
    • 使用嵌套for循环时,最好使用for-each循环,考虑下面的代码以便更好地理解。
    // Java program to demonstrate working of nested iterators
    // may not work as expected and throw exception.
    import java.util.*;
    
    public class Main
    {
        public static void main(String args[])
        {
            // Create a link list which stores integer elements
            List<Integer> l = new LinkedList<Integer>();
    
            // Now add elements to the Link List
            l.add(2);
            l.add(3);
            l.add(4);
    
            // Make another Link List which stores integer elements
            List<Integer> s=new LinkedList<Integer>();
            s.add(7);
            s.add(8);
            s.add(9);
    
            // Iterator to iterate over a Link List
            for (Iterator<Integer> itr1=l.iterator(); itr1.hasNext(); )
            {
                for (Iterator<Integer> itr2=s.iterator(); itr2.hasNext(); )
                {
                    if (itr1.next() < itr2.next())
                    {
                        System.out.println(itr1.next());
                    }
                }
            }
        }
    }
    

    输出:

    Exception in thread "main" java.util.NoSuchElementException
        at java.util.LinkedList$ListItr.next(LinkedList.java:888)
        at Main.main(Main.java:29)

    上面的代码抛出了java.util.NoSuchElementException。

    在上面的代码中,我们一次又一次地为itr1调用next()方法(即,对于List l)。现在我们正在推进迭代器,甚至没有检查它是否在集合中留下了更多元素(在内部循环中),因此我们推进迭代器的次数超过集合中导致NoSuchElementException的元素数量。

    for-each循环是为嵌套循环量身定制的。用以下代码替换迭代器Iterator代码。

    // Java program to demonstrate working of nested for-each
    import java.util.*;
    public class Main
    {
        public static void main(String args[])
        {
            // Create a link list which stores integer elements
            List<Integer> l=new LinkedList<Integer>();
    
            // Now add elements to the Link List
            l.add(2);
            l.add(3);
            l.add(4);
    
            // Make another Link List which stores integer elements
            List<Integer> s=new LinkedList<Integer>();
            s.add(2);
            s.add(4);
            s.add(5);
            s.add(6);
    
            // Iterator to iterate over a Link List
            for (int a:l)
            {
                for (int b:s)
                {
                    if (a<b)
                        System.out.print(a + " ");
                }
            }
        }
    }
    

    输出:

    2 2 2 3 3 3 4 4

    使用for-each循环或迭代器遍历集合可以提供相同的性能。在这里,表现我们指的是这两次遍历的时间复杂性。

    如果使用旧样式的C for循环进行迭代,那么我们可能会大大增加时间复杂度。

    //这里l是List,它可以是ArrayList / LinkedList,n是List的大小

    for (i=0;i<n;i++)
       System.out.println(l.get(i));

    这里,如果列表l是一个ArrayList,那么我们可以在O(1)时间内访问它,因为它被分配了连续的内存块(就像一个数组),即随机访问是可能的。但是如果集合是LinkedList,那么随机访问是不可能的,因为它没有分配连续的内存块,所以为了访问一个元素,我们必须遍历链接列表,直到你到达所需的索引,因此所用的时间访问元素的最坏情况是O(n)。

    对于没有随机访问的集合,Iterator和for-each循环比简单的循环更快,而在允许随机访问的集合中,for-each循环/ for循环/迭代器没有性能变化。

     
    转载请保留页面地址:https://www.breakyizhan.com/java/5281.html