1 遍历迭代器 iterator()
1.1 Iterator< E > iterator()
iterator() 返回一个通用的遍历迭代器 new Itr(),只有四个对外的方法
public Iterator< E> iterator ( ) {
return new Itr ( ) ;
}
private class Itr implements Iterator < E> {
int cursor;
int lastRet = - 1 ;
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 ( ) ;
}
}
@Override
@SuppressWarnings ( "unchecked" )
public void forEachRemaining ( Consumer< ? super E> consumer) {
Objects. requireNonNull ( consumer) ;
final int size = ArrayList. this . size;
int i = cursor;
if ( i >= size) {
return ;
}
final Object[ ] elementData = ArrayList. this . elementData;
if ( i >= elementData. length) {
throw new ConcurrentModificationException ( ) ;
}
while ( i != size && modCount == expectedModCount) {
consumer. accept ( ( E) elementData[ i++ ] ) ;
}
cursor = i;
lastRet = i - 1 ;
checkForComodification ( ) ;
}
final void checkForComodification ( ) {
if ( modCount != expectedModCount)
throw new ConcurrentModificationException ( ) ;
}
}
import java. util. ArrayList;
import java. util. Iterator;
public class IteratorTest {
public static void main ( String[ ] args) {
ArrayList< Integer> arrayList = new ArrayList < > ( ) ;
arrayList. add ( 10 ) ;
arrayList. add ( 20 ) ;
arrayList. add ( 30 ) ;
arrayList. add ( 40 ) ;
Iterator< Integer> iterator = arrayList. iterator ( ) ;
while ( iterator. hasNext ( ) ) {
Integer e = iterator. next ( ) ;
System. out. println ( "当前元素: " + e) ;
if ( e == 10 ) {
iterator. remove ( ) ;
}
if ( e == 20 ) {
iterator. forEachRemaining ( ( Integer integer) - > {
System. out. println ( "forEachRemaining 后的值: " + integer) ;
} ) ;
}
}
System. out. println ( ) ;
System. out. println ( "iterator 操作后的 arrayList --> " + arrayList) ;
}
}
1.2 列表遍历迭代器ListIterator< E > listIterator(int index)
ListIterator< E> listIterator() 相当于 ListIterator< E> listIterator(0),
public ListIterator< E> listIterator ( ) {
return new ListItr ( 0 ) ;
}
public ListIterator< E> listIterator ( int index) {
if ( index < 0 || index > size)
throw new IndexOutOfBoundsException ( "Index: " + index) ;
return new ListItr ( index) ;
}
ListItr extends Itr implements ListIterator 即 ListItr 也是一个 遍历器,只不过扩展了一些功能
private class ListItr extends Itr implements ListIterator < E> {
ListItr ( int index) {
super ( ) ;
cursor = index;
}
public boolean hasPrevious ( ) {
return cursor != 0 ;
}
public int nextIndex ( ) {
return cursor;
}
public int previousIndex ( ) {
return cursor - 1 ;
}
@SuppressWarnings ( "unchecked" )
public E previous ( ) {
checkForComodification ( ) ;
int i = cursor - 1 ;
if ( i < 0 )
throw new NoSuchElementException ( ) ;
Object[ ] elementData = ArrayList. this . elementData;
if ( i >= elementData. length)
throw new ConcurrentModificationException ( ) ;
cursor = i;
return ( E) elementData[ lastRet = i] ;
}
public void set ( E e) {
if ( lastRet < 0 )
throw new IllegalStateException ( ) ;
checkForComodification ( ) ;
try {
ArrayList. this . set ( lastRet, e) ;
} catch ( IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException ( ) ;
}
}
public void add ( E e) {
checkForComodification ( ) ;
try {
int i = cursor;
ArrayList. this . add ( i, e) ;
cursor = i + 1 ;
lastRet = - 1 ;
expectedModCount = modCount;
} catch ( IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException ( ) ;
}
}
}
代码测试: 注意 previous 会将指针前移,next 则会指针后移,取出来的元素就是操作的元素。
package cn. cerish. container. collection. arrayList;
import java. util. ArrayList;
import java. util. Iterator;
import java. util. ListIterator;
public class ListIteratorTest {
public static void main ( String[ ] args) {
ArrayList< Integer> arrayList = new ArrayList < > ( ) ;
arrayList. add ( 10 ) ;
arrayList. add ( 20 ) ;
arrayList. add ( 30 ) ;
arrayList. add ( 40 ) ;
ListIterator< Integer> listIterator = arrayList. listIterator ( ) ;
System. out. println ( "刚获得遍历器 listIterator,hasPrevious --> " + listIterator. hasPrevious ( ) ) ;
System. out. println ( "刚获得遍历器 listIterator,nextIndex --> " + listIterator. nextIndex ( ) ) ;
System. out. println ( "刚获得遍历器 listIterator,previousIndex --> " + listIterator. previousIndex ( ) ) ;
System. out. println ( "now arraylist -->" + arrayList) ;
System. out. println ( "================================================" ) ;
Integer integer = listIterator. next ( ) ;
System. out. println ( "获得遍历器的 next 元素: " + integer) ;
System. out. println ( "获得遍历器的 next 元素:hasPrevious --> " + listIterator. hasPrevious ( ) ) ;
System. out. println ( "获得遍历器的 next 元素:previous --> " + listIterator. previous ( ) ) ;
System. out. println ( "获得遍历器的 next 元素:nextIndex --> " + listIterator. nextIndex ( ) ) ;
System. out. println ( "获得遍历器的 next 元素:previousIndex --> " + listIterator. previousIndex ( ) ) ;
System. out. println ( "now arraylist -->" + arrayList) ;
System. out. println ( "================================================" ) ;
listIterator. set ( 100 ) ;
System. out. println ( "listIterator.set():,hasPrevious --> " + listIterator. hasPrevious ( ) ) ;
System. out. println ( "listIterator.set():,previous --> " + ( listIterator. hasPrevious ( ) ? listIterator. previous ( ) : - 1 ) ) ;
System. out. println ( "listIterator.set():,nextIndex --> " + listIterator. nextIndex ( ) ) ;
System. out. println ( "listIterator.set():,previousIndex --> " + listIterator. previousIndex ( ) ) ;
System. out. println ( "now arraylist -->" + arrayList) ;
System. out. println ( "================================================" ) ;
listIterator. add ( 50 ) ;
System. out. println ( "listIterator.add():,hasPrevious --> " + listIterator. hasPrevious ( ) ) ;
System. out. println ( "listIterator.add():,previous --> " + ( listIterator. hasPrevious ( ) ? listIterator. previous ( ) : - 1 ) ) ;
System. out. println ( "listIterator.add():,nextIndex --> " + listIterator. nextIndex ( ) ) ;
System. out. println ( "listIterator.add():,previousIndex --> " + listIterator. previousIndex ( ) ) ;
System. out. println ( "now arraylist -->" + arrayList) ;
}
}
1.3 分割迭代器ArrayListSpliterator< E >
将 ArrayList 分割成多个部分,并对其做一定的操作
static final class ArrayListSpliterator < E> implements Spliterator < E> {
private final ArrayList< E> list;
private int index;
private int fence;
private int expectedModCount;
ArrayListSpliterator ( ArrayList< E> list, int origin, int fence,
int expectedModCount) {
this . list = list;
this . index = origin;
this . fence = fence;
this . expectedModCount = expectedModCount;
}
private int getFence ( ) {
int hi;
ArrayList< E> lst;
if ( ( hi = fence) < 0 ) {
if ( ( lst = list) == null)
hi = fence = 0 ;
else {
expectedModCount = lst. modCount;
hi = fence = lst. size;
}
}
return hi;
}
public ArrayListSpliterator< E> trySplit ( ) {
int hi = getFence ( ) , lo = index, mid = ( lo + hi) >>> 1 ;
return ( lo >= mid) ? null :
new ArrayListSpliterator < E> ( list, lo, index = mid,
expectedModCount) ;
}
public boolean tryAdvance ( Consumer< ? super E> action) {
if ( action == null)
throw new NullPointerException ( ) ;
int hi = getFence ( ) , i = index;
if ( i < hi) {
index = i + 1 ;
@SuppressWarnings ( "unchecked" )
E e = ( E) list. elementData[ i] ;
action. accept ( e) ;
if ( list. modCount != expectedModCount)
throw new ConcurrentModificationException ( ) ;
return true ;
}
return false ;
}
public void forEachRemaining ( Consumer< ? super E> action) {
int i, hi, mc;
ArrayList< E> lst; Object[ ] a;
if ( action == null)
throw new NullPointerException ( ) ;
if ( ( lst = list) != null && ( a = lst. elementData) != null) {
if ( ( hi = fence) < 0 ) {
mc = lst. modCount;
hi = lst. size;
}
else
mc = expectedModCount;
if ( ( i = index) >= 0 && ( index = hi) <= a. length) {
for ( ; i < hi; ++ i) {
@SuppressWarnings ( "unchecked" )
E e = ( E) a[ i] ;
action. accept ( e) ;
}
if ( lst. modCount == mc)
return ;
}
}
throw new ConcurrentModificationException ( ) ;
}
public long estimateSize ( ) {
return ( long ) ( getFence ( ) - index) ;
}
public int characteristics ( ) {
return Spliterator. ORDERED | Spliterator. SIZED | Spliterator. SUBSIZED;
}
}
import java. util. ArrayList;
import java. util. ListIterator;
import java. util. Spliterator;
public class SplitIteratorTest {
private static String getFormatStr ( int num, int len) {
String integerMaxValueStr = Integer. toBinaryString ( num) ;
int a = len;
StringBuilder sb = new StringBuilder ( ) ;
int l = integerMaxValueStr. length ( ) ;
int i = 0 ;
for ( ; a > 0 ; -- a) {
if ( -- l >= 0 ) {
sb. append ( integerMaxValueStr. charAt ( l) ) ;
} else {
sb. append ( "0" ) ;
}
if ( ++ i % 4 == 0 ) {
if ( a > 1 ) {
sb. append ( "-" ) ;
}
i = 0 ;
}
}
return sb. reverse ( ) . toString ( ) ;
}
public static void main ( String[ ] args) {
ArrayList< Integer> arrayList = new ArrayList < > ( ) ;
arrayList. add ( 10 ) ;
arrayList. add ( 20 ) ;
arrayList. add ( 30 ) ;
arrayList. add ( 40 ) ;
System. out. println ( "当前 arrayList: " + arrayList) ;
System. out. println ( "======================================" ) ;
Spliterator< Integer> spliterator = arrayList. spliterator ( ) ;
System. out. println ( "spliterator 的状态: " + getFormatStr ( spliterator. characteristics ( ) , 32 ) ) ;
System. out. println ( "刚创建完 spliterator,spliterator中还有多少个元素: " + spliterator. estimateSize ( ) ) ;
spliterator. tryAdvance ( ( e) - > System. out. println ( "当前的元素: " + e) ) ;
System. out. println ( "执行完tryAdvance(), spliterator中还有多少个元素: " + spliterator. estimateSize ( ) ) ;
System. out. print ( "我是 foreach: 我是剩下的元素" ) ;
spliterator. forEachRemaining ( ( e) - > {
System. out. print ( "\t " + e) ;
} ) ;
System. out. println ( ) ;
System. out. println ( "======================================" ) ;
Spliterator< Integer> spliterator01 = spliterator. trySplit ( ) ;
System. out. print ( "我是 foreach: 我来遍历spliterator01 元素: " ) ;
spliterator. forEachRemaining ( ( e) - > {
System. out. print ( "\t " + e) ;
} ) ;
System. out. println ( ) ;
System. out. println ( "spliterator 的状态: " + getFormatStr ( spliterator. characteristics ( ) , 32 ) ) ;
}
}
characteristics 特征是用来描述元素的特征且限制某些行为,具体请看 Spliterator 篇了解。
2. foreach()
public void forEach ( Consumer< ? super E> action) {
Objects. requireNonNull ( action) ;
final int expectedModCount = modCount;
@SuppressWarnings ( "unchecked" )
final E[ ] elementData = ( E[ ] ) this . elementData;
final int size = this . size;
for ( int i= 0 ; modCount == expectedModCount && i < size; i++ ) {
action. accept ( elementData[ i] ) ;
}
if ( modCount != expectedModCount) {
throw new ConcurrentModificationException ( ) ;
}
}
测试代码,单纯拿来遍历没问题,但发生删除操作,就出事了,报错 ConcurrentModificationException
import java. util. ArrayList;
public class ForEachTest {
public static void main ( String[ ] args) {
ArrayList< Integer> arrayList = new ArrayList < > ( ) ;
arrayList. add ( 10 ) ;
arrayList. add ( 20 ) ;
arrayList. add ( 30 ) ;
arrayList. add ( 40 ) ;
arrayList. add ( 50 ) ;
arrayList. add ( 60 ) ;
System. out. println ( "============ 遍历 arrayList 的元素 ===========" ) ;
arrayList. forEach ( ( e) - > System. out. print ( e + "\t" ) ) ;
System. out. println ( ) ;
System. out. println ( "=========== 若发生改动 list 操作 ============" ) ;
arrayList. forEach ( e - > {
System. out. println ( "当前元素为: " + e) ;
arrayList. add ( 100 ) ;
} ) ;
}
}
3. replaceAll(UnaryOperator operator)
遍历所有的元素,根据传入的规则,进行整体的替换操作
@Override
@SuppressWarnings ( "unchecked" )
public void replaceAll ( UnaryOperator< E> operator) {
Objects. requireNonNull ( operator) ;
final int expectedModCount = modCount;
final int size = this . size;
for ( int i= 0 ; modCount == expectedModCount && i < size; i++ ) {
elementData[ i] = operator. apply ( ( E) elementData[ i] ) ;
}
if ( modCount != expectedModCount) {
throw new ConcurrentModificationException ( ) ;
}
modCount++ ;
}
import java. util. ArrayList;
public class ReplaceAllTest {
public static void main ( String[ ] args) {
ArrayList< Integer> arrayList = new ArrayList < > ( ) ;
arrayList. add ( 10 ) ;
arrayList. add ( 20 ) ;
arrayList. add ( 30 ) ;
System. out. println ( "============ 遍历 replaceAll() arrayList 的元素 ===========" ) ;
System. out. println ( "replaceAll() 前的 arrayList: " + arrayList) ;
arrayList. replaceAll ( ( e) - > e * 10 ) ;
System. out. println ( "replaceAll() 后的 arrayList: " + arrayList) ;
System. out. println ( "========= 若replaceAll()过程 发生改动 list 操作 ============" ) ;
arrayList. replaceAll ( ( e) - > {
arrayList. add ( 1000 ) ;
return e * 10 ;
}
) ;
}
}
4 foreach 与 iterator 的区别
会看 foreach 发生报错的地方,modCount 被修改了,即 remove 发生了 modCount 修改
if ( modCount != expectedModCount) {
throw new ConcurrentModificationException ( ) ;
}
private void fastRemove ( int index) {
modCount++ ;
int numMoved = size - index - 1 ;
if ( numMoved > 0 )
System. arraycopy ( elementData, index+ 1 , elementData, index,
numMoved) ;
elementData[ -- size] = null;
}
那问题来了,我想遍历,根据条件删除某一个元素,该怎么办呢?使用 iterator。
import java. util. ArrayList;
import java. util. Iterator;
public class IteratorTest {
public static void main ( String[ ] args) {
ArrayList< Integer> arrayList = new ArrayList < > ( ) ;
arrayList. add ( 10 ) ;
arrayList. add ( 20 ) ;
arrayList. add ( 30 ) ;
arrayList. add ( 40 ) ;
Iterator< Integer> iterator = arrayList. iterator ( ) ;
System. out. println ( "iterator 遍历前的 arrayList: " + arrayList) ;
Iterator< Integer> iterator1 = arrayList. iterator ( ) ;
while ( iterator1. hasNext ( ) ) {
Integer next = iterator1. next ( ) ;
if ( next == 20 ) iterator1. remove ( ) ;
}
System. out. println ( "iterator 遍历后的 arrayList: " + arrayList) ;
}
}
为什么 iterator.remove() 就可以?
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 ( ) ;
}
}
总结:foreach 循环删除会报错是因为 modCount 被修改,iterator 的 modCount 会修正,但关键的地方还是cursor指针,在修改之后,一直指向原本指向的元素的下标。 步骤解释 iterator.remove()
假装我是一个图:
下标 0 1 2 3 4 5 6 7 8 9
list : [ 10 20 30 40 50 60 70 80 90 100 ]
iterator : [ 10 20 30 40 50 60 70 80 90 100 ] cursor = 0 , laetRet = - 1
执行一次 iterator. next ( ) 后
list : [ 10 20 30 40 50 60 70 80 90 100 ]
iterator : [ 20 30 40 50 60 70 80 90 100 ] cursor = 1 , laetRet = 0
继续执行一次 iterator. next ( ) 后
list : [ 10 20 30 40 50 60 70 80 90 100 ]
iterator : [ 30 40 50 60 70 80 90 100 ] cursor = 2 , laetRet = 1
执行 iterator. remove ( ) 即执行 ArrayList. this . remove ( 1 ) ;
list : [ 10 30 40 50 60 70 80 90 100 ]
iterator : [ 30 40 50 60 70 80 90 100 ]
重点来了,到现在为止,cursor = 2 ,laetRet = 1 , 那么 cursor 指向了40 ,laetRet 指向了30 ,这不对啊
所以,cursor = lastRet = 1 指向原来的30 ,而原来的laetRet 指向被删除的20 ,应该取消指向,lastRet = - 1 ,修改modCount版本: expectedModCount = modCount;
此时cursor = 1 ,lastRet = - 1 ,继续执行一次 iterator. next ( ) 后
list : [ 10 30 40 50 60 70 80 90 100 ]
iterator : [ 40 50 60 70 80 90 100 ] cursor = 2 , laetRet = 1 , 又可以愉快的进行游戏了
5. 总结
ArrayList 有三种遍历器,通用遍历器的 iterator()、列表遍历器 listIterator()、数组列表分割遍历器 ArrayListSpliterator(),可根据实际情况选择使用 foreach 适用于遍历展示输出,replaceAll 适用于整体做同样的操作替换,如 整体元素+100,但如果涉及删除操作,使用 iterator 才是正确的选择。