文章目录
迭代器是属于设计模式之一,迭代器模式提供了一种方法来顺序访问一个聚合对象中各个元素,而不保留该对象的内部表示。
1)
Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
2)所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
3)Iterator仅用于遍历集合,Iterator本身并不存放对象。

通过观察类结构图的继承关系我们发现,集合的顶层接口Collection继承Iterable接口。
public interface Iterable<T> {
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
Iterator<T> iterator();
}
在Iterable接口中有一个Iterator方法,它返回一个Itertator对象。
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
}
| 返回值类型 | 方法名 | 功能 |
|---|---|---|
| boolean | hasNext() | 判断集合是否还有元素,如果返回 true 表示集合还有元素,返回 false 表示集合中没有元素;一般对集合的访问通过 while(hasNext()) 判断是否还需要遍历。 |
| E | next() | 获取集合中遍历的当前元素 ;一般先调用 hasNext() 方法判断是否存在元素,再调用 next() 获取元素,需要进行循环交替遍历集合中的元素。 |
| void | remove | 删除集合中的元素。 |
我们用ArrayList集合存放一些整型数据做示例,然后将其集合中的元素一一遍历打印输出。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TestDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(111);
list.add(222);
list.add(333);
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
int value = iterator.next();
System.out.print(value + " ");
}
}
}
运行结果:

观察运行结果我们发现,通过迭代器我们将ArrayList集合中的元素一一打印了出来。
在上述的示例中,迭代器是如何实现对集合的遍历呢?

①首先得到一个集合的迭代器Iterator iterator = list.iterator();
②进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置的元素111返回。
③再次进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置222的元素返回。
④再次进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置333的元素返回。
⑤再次进入while循环,调用hasNext()判断是否有下一个元素,返回false,循环结束。
在 迭代器的遍历过程中先通过hastNext()方法判断是否有下一个元素,如果存在下一个元素再调用next()方法获取元素,在这里next()方法先往后移动一个元素位置,再返回该位置的元素。因此,在调用next()方法之前必须要调用hastNext()方法进行检测;如果没有调用并且没有下一个元素,直接调用next()方法会抛出 NoSuchElementException异常。
一开始使用迭代器可能会觉得麻烦,但是如果用的Idea编译器是有快捷键的,输入itit再回车就会直接生成。

在Iterator接口中除了hasNext()和next()方法外,还有一个remove()方法,即删除集合中的元素。
如删除上述示例集合中的元素111
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings({"all"})
public class TestDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(111);
list.add(222);
list.add(333);
System.out.println("删除前:" + list);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer value = iterator.next();
if(value == 111) iterator.remove();
}
System.out.println("删除后" + list);
}
}
运行结果:

在Java集合中,以集合ArrayList为例,在使用中可能会遇到删除的需求场景,此时如果代码书写不当,极有可能会抛出java.util.ConcurrentModificationException异常信息。
在上述示例中用Iterator调用了迭代器remove()方法,如果在使用中不小心调用了集合中的remove()方法会发生什么?
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings({"all"})
public class TestDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(111);
list.add(222);
list.add(333);
System.out.println("删除前:" + list);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer value = iterator.next();
if(value == 111) list.remove(Integer.valueOf(111));
}
System.out.println("删除后" + list);
}
}
运行结果:

运行结果中抛出java.util.ConcurrentModificationException异常信息。这是因为触发了集合中并发修改的异常 接下来我们通过源码对抛出异常的原因进行剖析。
public Iterator<E> iterator() {
return new Itr();
}
在ArrayList集合的Iterator方法中,是通过返回Itr对象来获得迭代器的。Itr是ArrayList的一个内部类,它实现了Iterator接口,代码如下:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
Itr类属性
| 属性 | 含义 |
|---|---|
| cursor | 索引下标,表示下一个可以访问的元素的索引,默认值为 0 |
| lastRet | 索引下标,表示上一个元素的索引,默认值为 -1 |
| expectedModCount | 对集合修改的版本号,初始值为ModCount |
ModCount定义在AbstractList接口中,初始值为0,定义如下:
protected transient int modCount = 0;
ModCount是版本号,在对集合进行变更操作(增加、删除、修改等)的时候会对版本号进行 +1 操作。
结合上述代码进行抛出java.util.ConcurrentModificationException异常的解释。
①初始化ArrayList,添加三次元素,即三次调用add()方法,进行三次modCount++; 此时,
m
o
d
C
o
u
n
t
=
3
,
s
i
z
e
=
3
;
\color{red}{modCount = 3,size = 3;}
modCount=3,size=3;
②初始化Iterator迭代器进行循环,此时,
e
x
p
e
c
t
e
d
M
o
d
C
o
u
n
t
=
m
o
d
C
o
u
n
t
=
3
,
\color{red}{expectedModCount = modCount=3,}
expectedModCount=modCount=3,
c
u
r
s
o
r
=
0
,
l
a
s
t
R
e
t
=
−
1
\color{red}{cursor=0,lastRet = -1}
cursor=0,lastRet=−1
③进行hasNext判断,cursor != size;成立,进入循环
④调用next()方法,首先进行checkForComodification()校验,
m
o
d
C
o
u
n
t
=
=
e
x
p
e
c
t
e
d
M
o
d
C
o
u
n
t
\color{red}{modCount == expectedModCount}
modCount==expectedModCount,校验通过,返回值,此时
l
a
s
t
R
e
t
=
0
;
c
u
r
s
o
r
=
1
\color{red}{lastRet = 0;cursor = 1}
lastRet=0;cursor=1
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
⑤调用集合remove()方法,modCount++;,此时
m
o
d
C
o
u
n
t
=
4
;
s
i
z
e
=
2
\color{red}{modCount = 4;size = 2}
modCount=4;size=2
⑥再次调用hasNext()方法判断,cursor != size;成立,进入循环
⑦调用next()方法进行校验,
m
o
d
C
o
u
n
t
!
=
e
x
p
e
c
t
e
d
M
o
d
C
o
u
n
t
\color{red}{modCount != expectedModCount}
modCount!=expectedModCount,校验未通过,抛出java.util.ConcurrentModificationException异常
总结:
①在使用迭代器的
remove()操作时,会将更新后的modCount给expectedModCount,两者会得到同步,但是在调用集合的remove()方法后,两个不会进行同步,进而导致在checkForComodification()校验时不通过,抛出java.util.ConcurrentModificationException异常。
②所以,在单线程下使用迭代器是没有问题的,但是在多线程下同时操作集合就不允许了,可以通过fail-fast快速失败机制,快速判断是否存在同时操作问题。因此,集合在多线程下使用是不安全的。
增强for循环可以代替Iterator迭代器,可以把它看做简化版的Iterator,和迭代器本质一样,其实它的底层实现就是Iterator迭代器,只能用于遍历集合或数组。

import java.util.ArrayList;
import java.util.List;
public class TestDemo03 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(111);
list.add(222);
list.add(333);
System.out.println("====增强for循环遍历集合====");
for(Integer i : list) {
System.out.print(i + " ");
}
System.out.println();
System.out.println("====增强for循环遍历数组====");
int[] arr = {1,2,3,4,5,6};
for (int i : arr) {
System.out.print(i + " ");
}
}
}
运行结果:

与迭代器一样,增强for循环也有快捷键,输入I回车即可快速生成。

我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.
Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur