程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 詳解JAVA中的for-each輪回與迭代

詳解JAVA中的for-each輪回與迭代

日期:2017/7/27 17:31:10      編輯:關於JAVA

詳解JAVA中的for-each輪回與迭代。本站提示廣大學習愛好者:(詳解JAVA中的for-each輪回與迭代)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解JAVA中的for-each輪回與迭代正文


在進修java中的collection時留意到,collection條理的根接口Collection完成了Iterable<T>接口(位於java.lang包中),完成這個接口許可對象成為 "foreach" 語句的目的,而此接口中的獨一辦法,完成的就是前往一個在一組 T 類型的元素長進行迭代的迭代器。

1、迭代器Iterator

接口:Iterator<T>

public interface Iterator<E>{
  boolean hasNext(); 
 E next(); 
 void remove();
 }

檢查Iterator接口API可以曉得,這是對collection停止迭代的迭代器。迭代器許可挪用者應用界說優越的語義在迭代時代從迭代器所指向的 collection 移除元素。

特別值得留意的是此迭代器remove()辦法的應用:從迭代器指向的 collection 中移除迭代器前往的最初一個元素(可選操作)。每次挪用 next 只能挪用一次此辦法。假如停止迭代時用挪用此辦法(remove辦法)以外的其他方法修正了該迭代器所指向的 collection,則迭代器的行動是不肯定的。 接口設計人員在設計Iterator<T>接口的時刻曾經指出,在停止迭代時假如挪用了除迭代器的remove()辦法修正了該迭代器所指向的collection,則會形成不肯定的效果。詳細湧現甚麼效果依迭代器的詳細完成而定。針對這類不肯定的效果能夠湧現的情形,在進修ArrayList時碰到了個中一種:迭代器拋出 ConcurrentModificationException異常。詳細異常情形以下代碼所示:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class ItaratorTest {

  public static void main(String[] args) {
    Collection<String> list = new ArrayList<String>();
    list.add("Android");
    list.add("IOS");
    list.add("Windows Mobile");

    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
      String lang = iterator.next();
      list.remove(lang);//will throw ConcurrentModificationException
    }
  }

}

此段代碼在運轉時會拋出ConcurrentModificationException異常,由於我們在迭代器運轉時代沒有效iterator的remove()辦法來刪除元素,而是應用ArrayList的 remove()辦法轉變了迭代器所指向的collection。這就違背了迭代器的設計准繩,所以產生了異常。

所報異常情形以下所示:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at Text.ItaratorTest.main(ItaratorTest.java:17)

2、for-each輪回與迭代器Iterator<T>

從Java5起,在Java中有了for-each輪回,可以用來輪回遍歷collection和array。Foreach輪回許可你在無需堅持傳統for輪回中的索引,或在應用iterator /ListIterator(ArrayList中的一種迭代器完成)時無需挪用while輪回中的hasNext()辦法就可以遍歷collection。for-each輪回簡化了任何Collection或array的遍歷進程。然則應用foreach輪回也有兩點須要留意。

應用foreach輪回的對象,必需完成了Iterable<T>接口

請看以下示例:

import java.util.ArrayList;

public class ForeachTest1 {

  public static void main(String args[]) {
    CustomCollection<String> myCollection = new CustomCollection<String>();
    myCollection.add("Java");
    myCollection.add("Scala");
    myCollection.add("Groovy");

    // What does this code will do, print language, throw exception or
    // compile time error
    for (String language : myCollection) {
      System.out.println(language);
    }
  }

  private class CustomCollection<T> {
    private ArrayList<T> bucket;

    public CustomCollection() {
      bucket = new ArrayList();
    }

    public int size() {
      return bucket.size();
    }

    public boolean isEmpty() {
      return bucket.isEmpty();
    }

    public boolean contains(T o) {
      return bucket.contains(o);
    }

    public boolean add(T e) {
      return bucket.add(e);
    }

    public boolean remove(T o) {
      return bucket.remove(o);
    }

  }
}

上述代碼將沒法經由過程編譯,這是由於代碼中的CustomCollection類沒有完成Iterable<T>接口,編譯期的報錯以下:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
    Can only iterate over an array or an instance of java.lang.Iterable

    at Text.ForeachTest1.main(ForeachTest1.java:15)

現實上,無需比及編譯時才發明報錯,eclipse會在這段代碼寫完以後就會在foreach輪回處顯示毛病:Can only iterate over an array or an instance of java.lang.Iterable

從上述示例可以再次獲得確認的是,foreach輪回只實用於完成了Iterable<T>接口的對象。因為一切內置Collection類都完成了java.util.Collection接口,曾經繼續了Iterable,所認為懂得決上述成績,可以選擇簡略地讓CustomCollection完成Collection接口或許繼續AbstractCollection。處理方法以下:

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Iterator;

public class ForeachTest {
  public static void main(String args[]) {
    CustomCollection<String> myCollection = new CustomCollection<String>();
    myCollection.add("Java");
    myCollection.add("Scala");
    myCollection.add("Groovy");
    for (String language : myCollection) {
      System.out.println(language);
    }
  }

  private static class CustomCollection<T> extends AbstractCollection<T> {
    private ArrayList<T> bucket;

    public CustomCollection() {
      bucket = new ArrayList();
    }

    public int size() {
      return bucket.size();
    }

    public boolean isEmpty() {
      return bucket.isEmpty();
    }

    public boolean contains(Object o) {
      return bucket.contains(o);
    }

    public boolean add(T e) {
      return bucket.add(e);
    }

    public boolean remove(Object o) {
      return bucket.remove(o);
    }

    @Override
    public Iterator<T> iterator() {
      // TODO Auto-generated method stub
      return bucket.iterator();
    }
  }
}

2.foreach輪回的外部完成也是依附Iterator停止完成的

為了驗證foreach輪回是應用Iterator作為外部完成這一現實,我們仍然采取本文最開端的實例停止驗證:

public class ItaratorTest {

  public static void main(String[] args) {
    Collection<String> list = new ArrayList<String>();
    list.add("Android");
    list.add("IOS");
    list.add("Windows Mobile");

    // example1
    // Iterator<String> iterator = list.iterator();
    // while (iterator.hasNext()) {
    // String lang = iterator.next();
    // list.remove(lang);
    // }

    // example 2
    for (String language : list) {
      list.remove(language);
    }
  }

}

法式運轉時所報異常:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at Text.ItaratorTest.main(ItaratorTest.java:22)

此異常正解釋了for-each輪回外部應用了Iterator來遍歷Collection,它也挪用了Iterator.next(),這會檢討(元素的)變更並拋出ConcurrentModificationException。

總結:

  • 在遍歷collection時,假如要在遍歷時代修正collection,則必需經由過程Iterator/listIterator來完成,不然能夠會產生“不肯定的效果”。
  • foreach輪回經由過程iterator完成,應用foreach輪回的對象必需完成Iterable接口

以上就是本文的全體內容,願望對年夜家的進修有所贊助,也願望年夜家多多支撐。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved