iterable接口

整个接口框架关系如下(来自百度百科):

iterable接口其实是java集合大家庭的最顶级的接口之一了,实现这个接口,可以视为拥有了获取迭代器的能力。Iterable接口出现在JDK1.5,那个时候只有iterator()方法,主要是定义了迭代集合内元素的规范。

实现了Iterable接口,我们可以使用增强的for循环,即

for(String str : lists){
System.out.println(str);
}

1. 内部定义的方法

java集合最源头的接口,实现这个接口的作用主要是集合对象可以通过迭代器去遍历每一个元素。

源码如下:

// 返回一个内部元素为T类型的迭代器(JDK1.5只有这个接口)
Iterator<T> iterator(); // 遍历内部元素,action意思为动作,指可以对每个元素进行操作(JDK1.8添加)
default void forEach(Consumer<? super T> action) {} // 创建并返回一个可分割迭代器(JDK1.8添加),分割的迭代器主要是提供可以并行遍历元素的迭代器,可以适应现在cpu多核的能力,加快速度。
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}

从上面可以看出,foreach迭代以及可分割迭代,都加了default关键字,这个是Java 8 新的关键字,以前接口的所有接口,具体子类都必须实现,而对于deafult关键字标识的方法,其子类可以不用实现,这也是接口规范发生变化的一点。

下面我们分别展示三个接口的调用:

1.1 iterator()方法

iterator()方法,是接口中的核心方法,主要是获取迭代器,获取到的iteratornext(),hasNext(),remove()等方法。

public static void iteratorHasNext(){
List<String> list=new ArrayList<String>();
list.add("Jam");
list.add("Jane");
list.add("Sam");
// 返回迭代器
Iterator<String> iterator=list.iterator();
// hashNext可以判断是否还有元素
while(iterator.hasNext()){
//next()作用是返回当前指针指向的元素,之后将指针移向下个元素
System.out.println(iterator.next());
}
}

当然也可以使用for-each loop方式遍历

for (String item : list) {
System.out.println(item);
}

但是实际上,这种写法在class文件中也是会转成迭代器形式,这只是一个语法糖。class文件如下:

public class IterableTest {
public IterableTest() { }
public static void main(String[] args) {
iteratorHasNext();
}
public static void iteratorHasNext() {
List<String> list = new ArrayList();
list.add("Jam");
list.add("Jane");
list.add("Sam");
Iterator<String> iterator = list.iterator();
Iterator var2 = list.iterator();
while(var2.hasNext()) {
String item = (String)var2.next();
System.out.println(item);
}
}
}

需要注意的一点是,迭代遍历的时候,如果删除或者添加元素,都会抛出修改异常,这是由于快速失败【fast-fail】机制。

    public static void iteratorHasNext(){
List<String> list=new ArrayList<String>();
list.add("Jam");
list.add("Jane");
list.add("Sam");
for (String item : list) {
if(item.equals("Jam")){
list.remove(item);
}
System.out.println(item);
}
}

从下面的错误我们可以看出,第一个元素是有被打印出来的,也就是remove操作是成功的,只是遍历到第二个元素的时候,迭代器检查,发现被改变了,所以抛出了异常。

Jam
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at IterableTest.iteratorHasNext(IterableTest.java:15)
at IterableTest.main(IterableTest.java:7)

1.2 forEach()方法

其实就是把对每一个元素的操作当成了一个对象传递进来,对每一个元素进行处理。

    default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}

当然像ArrayList自然也是有自己的实现的,那我们就可以使用这样的写法,简洁优雅。forEach方法在java8中参数是java.util.function.Consumer,可以称为消费行为或者说动作类型。

list.forEach(x -> System.out.print(x));

同时,我们只要实现Consumer接口,就可以自定义动作,如果不自定义,默认迭代顺序是按照元素的顺序。

public class ConsumerTest {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Jam");
list.add("Jane");
list.add("Sam");
MyConsumer myConsumer = new MyConsumer();
Iterator<String> it = list.iterator();
list.forEach(myConsumer);
}
static class MyConsumer implements Consumer<Object> {
@Override
public void accept(Object t) {
System.out.println("自定义打印:" + t);
} } }

输出的结果:

自定义打印:Jam
自定义打印:Jane
自定义打印:Sam

1.3 spliterator()方法

这是一个为了并行遍历数据元素而设计的迭代方法,返回的是Spliterator,是专门并行遍历的迭代器。以发挥多核时代的处理器性能,java默认在集合框架中提供了一个默认的Spliterator实现,底层也就是Stream.isParallel()实现的,我们可以看一下源码:

    // stream使用的就是spliterator
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
Objects.requireNonNull(spliterator);
return new ReferencePipeline.Head<>(spliterator,
StreamOpFlag.fromCharacteristics(spliterator),
parallel);
}

使用的方法如下:

    public static void spliterator(){
List<String> list = Arrays.asList("1", "2", "3","4","5","6","7","8","9","10");
// 获取可迭代器
Spliterator<String> spliterator = list.spliterator();
// 一个一个遍历
System.out.println("tryAdvance: ");
spliterator.tryAdvance(item->System.out.print(item+" "));
spliterator.tryAdvance(item->System.out.print(item+" "));
System.out.println("\n-------------------------------------------"); // 依次遍历剩下的
System.out.println("forEachRemaining: ");
spliterator.forEachRemaining(item->System.out.print(item+" "));
System.out.println("\n------------------------------------------"); // spliterator1:0~10
Spliterator<String> spliterator1 = list.spliterator();
// spliterator1:6~10 spliterator2:0~5
Spliterator<String> spliterator2 = spliterator1.trySplit();
// spliterator1:8~10 spliterator3:6~7
Spliterator<String> spliterator3 = spliterator1.trySplit();
System.out.println("spliterator1: ");
spliterator1.forEachRemaining(item->System.out.print(item+" "));
System.out.println("\n------------------------------------------");
System.out.println("spliterator2: ");
spliterator2.forEachRemaining(item->System.out.print(item+" "));
System.out.println("\n------------------------------------------");
System.out.println("spliterator3: ");
spliterator3.forEachRemaining(item->System.out.print(item+" "));
}
  • tryAdvance() 一个一个元素进行遍历
  • forEachRemaining() 顺序地分块遍历
  • trySplit()进行分区形成另外的 Spliterator,使用在并行操作中,分出来的是前面一半,就是不断把前面一部分分出来

结果如下:

tryAdvance:
1 2
-------------------------------------------
forEachRemaining:
3 4 5 6 7 8 9 10
------------------------------------------
spliterator1:
8 9 10
------------------------------------------
spliterator2:
1 2 3 4 5
------------------------------------------
spliterator3:
6 7

还有一些其他的用法在这里就不列举了,主要是trySplit()之后,可以用于多线程遍历。理想的时候,可以平均分成两半,有利于并行计算,但是不是一定平分的。

总结

以上可以得知,iterable接口,主要是定义了迭代遍历的规范,这个接口的作用是获取迭代器,迭代器在JDK1.8版本增加了可分割迭代器,更有利于并发处理。iterable接口,从字面意义来说,就是可以迭代的意思,可以理解为实现这个接口的集合类获得了迭代遍历的能力,同时它也是集合的顶级接口,Collection接口继承了它。

此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~

技术之路不在一时,山高水长,纵使缓慢,驰而不息。

公众号:秦怀杂货店

Java集合【3】-- iterable接口超级详细解析的更多相关文章

  1. Java集合【7】--List接口超级详细解析

    目录 1.List接口的特性 2.List接口的源码解析 3.相关子类介绍 3.1 ArrayList 3.1.1 成员变量 3.1.2 构造方法 3.1.3 常用增删改查方法 添加元素 查询元素 更 ...

  2. Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例

    概要  前面,我们已经学习了ArrayList,并了解了fail-fast机制.这一章我们接着学习List的实现类——LinkedList.和学习ArrayList一样,接下来呢,我们先对Linked ...

  3. Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例

    概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...

  4. Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

  5. 【转】Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

  6. Java 集合系列07之 Stack详细介绍(源码解析)和使用示例

    概要 学完Vector了之后,接下来我们开始学习Stack.Stack很简单,它继承于Vector.学习方式还是和之前一样,先对Stack有个整体认识,然后再学习它的源码:最后再通过实例来学会使用它. ...

  7. 【转】 Java 集合系列07之 Stack详细介绍(源码解析)和使用示例

    概要 学完Vector了之后,接下来我们开始学习Stack.Stack很简单,它继承于Vector.学习方式还是和之前一样,先对Stack有个整体认识,然后再学习它的源码:最后再通过实例来学会使用它. ...

  8. (一)java集合框架——Iterable

    Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...

  9. Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例

    概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解Arra ...

随机推荐

  1. 如何做好智能家居工业物联网串口转WiFi/4G/以太网无线AP方案的物联网WiFi模块选型

    2020年一场突如其来的灾难袭来,各大经济市场在不同程度被按下了"暂停键".物联网控制作为新兴行业优势凸显出来,其无接触式的交互方式,远程控制,智能控制车间,给人民带来安全.智能的 ...

  2. TCP 队列溢出了

    一.TCP 队列 1.syns queue:半连接队列 TCP 三次握手(参考:TCP建立连接之三次握手),第一步,服务端接收到客户端发送的 syn 消息后,将连接信息放入 syns queue,此时 ...

  3. [Luogu P2891/POJ 3281/USACO07OPEN ]吃饭Dining

    传送门:https://www.luogu.org/problemnew/show/P2891 题面 \ Solution 网络流 先引用一句真理:网络流最重要的就是建模 今天这道题让我深有体会 首先 ...

  4. Exception in MIPS

    介绍 分支.跳转.异常(包括硬件中断)是三种改变控制流的事件. 同步异常是指程序执行到固定位置必定触发且每次现象一致的异常,如算术溢出异常.未定义指令异常.缺页异常等. 异步异常与当前执行程序无关,如 ...

  5. 7_Reverse Integer

    7.Reverse Integer Given a 32-bit signed integer, reverse digits of an integer. Example 1: Input: 123 ...

  6. laravel 多表字段关联查询

    public function items() { return $this->belongsToMany('App\Model\Cz\CzCourse', 'cz_picture_course ...

  7. VirtualBox上桥接方式安装CentOS之后借助宿主上网

    VirtualBox上桥接方式安装CentOS之后借助宿主上网: 修改centos文件: 1 vi  /etc/sysconfig/network-scripts/ifcfg-eth0 增加以下几项: ...

  8. Jave正则的实现

    java的正则实现需要先导入 java.util.regex. java.util.regex 包主要包括以下三个类: Pattern 类: pattern 对象是一个正则表达式的编译表示.Patte ...

  9. 从头学起Verilog(三):Verilog逻辑设计

    引言 经过了组合逻辑和时序逻辑的复习,终于到了Verilog部分.这里主要介绍Verilog一些基础内容,包括结构化模型.TestBench编写和仿真.真值表模型. 这部分内容不多,也都十分基础,大家 ...

  10. 创建一个自定义名称的Ceph集群

    前言 这里有个条件,系统环境是Centos 7 ,Ceph 的版本为Jewel版本,因为这个组合下是由systemctl来进行服务控制的,所以需要做稍微的改动即可实现 准备工作 部署mon的时候需要修 ...