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));
复制代码
相关文章
相关标签/搜索