java 中的迭代器

迭代器如何使用

本來的遍歷是這樣的,java

List<Integer> list = new ArrayList<>();
//add
for(int i  =  0 ;i < list;i++ ){
  System.out.println(list.get(i));
}
複製代碼

而用了迭代器以後能夠是這樣的bash

Iterator<Integer> iterator = list.iterator();
    while (iterator.hasNext()){
        System.out.println(iterator.next());
}
複製代碼

或者這樣,數據結構

for (Integer i:list){
    System.out.println(i);
}
複製代碼

java8 以後能夠用ide

list.forEach(item -> System.out.println(item));
//或者更加精簡
list.forEach(System.out::println);
複製代碼

爲什麼要用迭代器?

舉個例子,好比要遍歷 LinkedList性能

若是不用迭代器,有些新手會寫成這樣測試

for(int i = 0 ; i < linkedList.size(); i++){
    System.out.println(list.get(i));
}
複製代碼

知道,LinkedList 的數據結構的朋友,應該會知道這樣遍歷的時候複雜度會是 O(n^2) 而 LinkedList 的遍歷本應該是 O(n)。 這只是個簡單的例子,以小見大吧。面對未知的數據結構,或者在不熟悉項目且時候很緊,逼着要用之前的人寫的數據結構的時候,若是還要用最原始的方式進行遍歷,就會莫名其妙地給程序「留有優化的空間」。優化

也就是說,若是用了遍歷器模式,就在原來的數據結構上創建一個新的抽象,更加方便地進行遍歷。ui

構造一個迭代器

從上面一個例子能夠看到this

Iterator<Integer> iterator = list.iterator();
    while (iterator.hasNext()){
        System.out.println(iterator.next());
}
複製代碼

好比有一個類是 Teacher ,他管理了不少學生。想經過這種方式遍歷要怎樣作呢?這樣就能夠了。spa

public class Teacher  {

    Student students[];

    public Teacher(Student[] students) {
        this.students = students;
    }

    public Iterator<Student> iterator() {
        return new Iterator<Student>() {

            int i = 0;

            @Override
            public boolean hasNext() {
                return students != null && i != students.length;
            }

            @Override
            public Student next() {
                return students[i++];
            }
        };
    }
}
複製代碼

若是是要作到相似容器那種 for-each 的效果?好比是這樣。

for (Student s : teacher) {
    System.out.println(s);
}

teacher.forEach(System.out::println);
複製代碼

那就要額外實現一下 Iterable 接口了。

public class Teacher implements Iterable<Student> {
  //...
    @Override
    public Iterator<Student> iterator() {
    //...同上
    }
  
    @Override
    public void forEach(Consumer<? super Student> action) {
        for(Student s: students){
            action.accept(s);
        }
    }

     /** * 這個是用於 java8 的並行 foreach 的,運用的模式相似於迭代是,比較複雜先不寫了。 **/
    @Override
    public Spliterator<Student> spliterator() {
        //TODO
        return null;
    }
}
複製代碼

最後看看各個不一樣寫法的迭代的性能

用 100 萬條 簡單測試一下

int size = 1000000;
List<Integer> nums = new ArrayList<>();

for (int i = 0; i < size; i++) {
    nums.add(i);
}

//傳統方式 用時 6ms
long start = System.currentTimeMillis();

for(int i = 0 ; i <size ;i++){
    nums.get(i);
}

long end = System.currentTimeMillis();
System.out.println("傳統方式:" + (end - start));


//使用迭代器 用時:16ms
start = System.currentTimeMillis();
Iterator<Integer> iterator = nums.iterator();
while (iterator.hasNext()) {
    iterator.next();
}
end =System.currentTimeMillis();
System.out.println("迭代器:" + (end - start));


//使用 foreach 語法糖 用時:17ms
start = System.currentTimeMillis();

for (Integer num : nums) {
}

end = System.currentTimeMillis();
System.out.println("foreach:" + (end - start));


//使用 lambda 接口 語法糖 用時:39ms
start =  System.currentTimeMillis();

nums.forEach(num -> {});

end =  System.currentTimeMillis();
System.out.println("lambda:" + (end - start));

//使用 stream 接口語法糖 用時: 14ms
start = System.currentTimeMillis();

nums.stream().forEach(s->{});

end = System.currentTimeMillis();
System.out.println("stream 接口語法糖:" + (end - start));
複製代碼
相關文章
相關標籤/搜索