JDK源码阅读-Iterable接口

概述

java.lang.Iterable接口是java集合的顶级接口之一,因为接口Collection继承了该接口,使得所有实现Collection的集合类都间接实现了Iterable接口。在JavaDoc中是这样定义Iterable接口的作用:

 // Implementing this interface allows an object to be the target of the "for-each loop" statement.
复制代码

也就是,实现Iterable接口后,对象便可以使用for-each循环了。在JDK8之前,Iterable接口只有一个方法:iterator()。在JDK8时,新加了forEachspliterator两个方法。

public interface Iterable<T> {
    Iterator<T> iterator();
    
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
    
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}
复制代码

方法

iterator()方法

通过这个方法返回一个Iterator接口的实现,以遍历集合的元素。Iterator接口的讨论在本人的另一篇文章中已经介绍了:传送门

forEach(Consumer<? super T>)方法

forEach方法是JDK8中新增的一个default方法,官方的文档:

     * Performs the given action for each element of the {@code Iterable}
     * until all elements have been processed or the action throws an
     * exception.  Unless otherwise specified by the implementing class,
     * actions are performed in the order of iteration (if an iteration order
     * is specified).  Exceptions thrown by the action are relayed to the
     * caller.
复制代码

大概的意思是:

  1. forEach方法接受一个Consumer的消费行为;
  2. 将集合中的每个元素作为消费行为的accept方法的参数执行,直到每个元素都处理完毕或者抛出异常;
  3. 除非指定了消费行为action的实现,否则默认情况下是按元素顺序依次迭代。

举个栗子,说明一下JDK8前后迭代元素的方法:

package me.ifight.controller;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;

/**
 * @description: 测试
 * @author: tjliu
 * @create: 2019-01-15 22:45
 **/
public class testController {
    public static void main(String[] args) {
        List<String> xxBrothers = new ArrayList<>();
        xxBrothers.add("王宝强");
        xxBrothers.add("陈羽凡");
        xxBrothers.add("贾乃亮");
        String brother = null;

        System.out.println("JDK5 start...");
        Iterator<String> it = xxBrothers.iterator();
        while (it.hasNext()) {
            brother = it.next(); // 经典遍历方式
            System.out.println("next brother: " + brother);
        }
        System.out.println("JDK5 end...\n");

        System.out.println("JDK8 start...");
        xxBrothers.forEach(s -> {
            System.out.println("forEach brother: " + s); // 大热的forEach遍历
        });
        System.out.println("JDK8 end...\n");

        System.out.println("JDK8,使用自定义的消费动作行为,start...");
        MyConsumer myConsumer = new MyConsumer();
        xxBrothers.forEach(myConsumer); // 自定义遍历行为
        System.out.println("JDK8,使用自定义的消费动作行为,end...");

    }

    // 自定义消费行为动作Consumer action
    static class MyConsumer implements Consumer<Object> {
        @Override
        public void accept(Object t) {
            String newStr = "兄弟" + (String) t;
            System.out.println("consumer: " + newStr);
        }

    }
}

-----------------output----------------
JDK5 start...
next brother: 王宝强
next brother: 陈羽凡
next brother: 贾乃亮
JDK5 end...

JDK8 start...
forEach brother: 王宝强
forEach brother: 陈羽凡
forEach brother: 贾乃亮
JDK8 end...

JDK8,使用自定义的消费动作行为,start...
consumer: 兄弟王宝强
consumer: 兄弟陈羽凡
consumer: 兄弟贾乃亮
JDK8,使用自定义的消费动作行为,end...
复制代码

spliterator()方法

Spliterator(splitable iterator可分割迭代器)接口是Java为了并行遍历数据源中的元素而设计的迭代器,这个可以类比最早Java提供的顺序遍历迭代器Iterator,但一个是顺序遍历,一个是并行遍历。

Q&A

  1. Iterable接口和Iterator接口的区别?
  • Iterator把一个集合的实现和遍历进行了分离,使用Iterator对象可以不用关心具体的集合对象的具体类型和内部实现。
  • 而Iterable接口是为了实现for-each循环设计的,Iterable的接口表示直接返回了Iterator对象,最终还是使用Iterator来进行集合的遍历工作
  1. 为什么不把Iterator和Iterable两个接口合并,直接在Iterable里面定义hasNext(),next()等方法呢。或者为什么Collection接口不直接继承Iterator,放弃Iterable接口? 原因有两点:
  • Iterator接口的核心方法next()或者hasNext()是依赖于迭代器的当前迭代位置的,如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代的位置信息。当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。但即时这样,Collection也只能同时存在一个当前迭代位置。而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。多个迭代器是互不干扰的。
  • 实现了Iterable的类可以实现多个Iterator内部类,例如LinkedList中的ListItrDescendingIterator两个内部类,就分别实现了双向遍历和逆序遍历。通过返回不同的Iterator实现不同的遍历方式,这样更加灵活。如果把两个接口合并,就没法返回不同的Iterator实现类了。示例代码:
import java.util.*;

public class MutilIterator implements Iterable<String> {
    private String[] words = "May I get offers this summer.".split(" ");

    //默认的迭代器,前向遍历
    public Iterator<String> iterator() {
       //匿名内部类
        return new Iterator<String>() {
            private int index = 0;
            public boolean hasNext() {return index < words.length;}
            public String next() { return words[index++];    }
            public void remove() { // Not implemented
                throw new UnsupportedOperationException();
            }
        };
    }

    //反向迭代器
    public Iterable<String> reverseIterator() {
        return new Iterable<String>() {
            @Override
            public Iterator<String> iterator() {
                return new Iterator<String>() {
                    private int index = words.length - 1;
                    public boolean hasNext() {return index > -1; }
                    public String next() {return words[index--]; }
                    public void remove() { // Not implemented
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }
    
    //随机迭代器,注意这里不是创建一个新的Iterator,而是返回了一个打乱的List中的迭代器
    public Iterable<String> randomized() {
        return new Iterable<String>() {
            public Iterator<String> iterator() {
                List<String> shuffled = new ArrayList<>(Arrays.asList(words));
                Collections.shuffle(shuffled, new Random(47));
                return shuffled.iterator();
            }
        };
    }
    
    public static void main(String[] args) {
        MutilIterator mi = new MutilIterator();
       //默认的迭代器
        for (String String : mi) {
            System.out.print(String + " ");
        }
        System.out.println();
       //反向迭代器
        for (String String : mi.reverseIterator()) {
            System.out.print(String + " ");
        }
        System.out.println();
        //随机迭代器
        for (String String : mi.randomized()) {
            System.out.print(String + " ");
        }
    }
}

-----------------output---------------
May I get offers this summer. 
summer. this offers get I May 
I this offers summer. May get
复制代码

相关阅读

JDK源码阅读-Iterator接口

参考链接

Java中Iterable和Iterator接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值