ArrayList與迭代器模式
阿新 • • 發佈:2019-02-03
本文主要講解迭代器模式在ArrayList原始碼中的使用。
迭代器模式(Iterator Pattern):提供一種方法來訪問聚合物件中的各個元素,而不用暴露這個物件的內部表示。在Java中,ArrayList的迭代器有兩種:Iterator和ListIterator。
Iterator
迭代器是一個用來遍歷並選擇序列中的物件。Java的Iterator的只能單向移動。
例子
在寫如何實現之前,先看一個使用迭代器Iterator的小例子:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
@org.junit.Test
public void test() {
List list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String str = (String) iterator.next();
System.out.println(str);
iterator.remove();
}
System.out.println(list.size());
}
}
執行結果
1
2
3
4
0
方法
- iterator(),list.iterator()用來從容器物件中返回一個指向list開始處的迭代器。
- next(),獲取序列中的下個元素。
- hasNext(),檢查序列中向下是否還有元素。
- remove(),將迭代器最近返回的一個元素刪除。這也意味著呼叫remove()前需要先呼叫next()。
實現
在設計模式(16)-迭代器模式這一文章中曾講過,迭代器模式中有四個角色:
- 抽象聚合類Aggregate。在ArrayList的Iterator迭代器實現中,沒有抽象聚合類。雖然它實現了AbstractList,實現了List,但它向外部提供的建立迭代器的方法iterator()是它自己的。
- 具體聚合類ConcreteAggregate。在ArrayList的Iterator迭代器實現中,指的是ArrayList。
- 抽象迭代器Iterator。在ArrayList的Iterator迭代器實現中,指的是Iterator介面。
- 具體迭代器ConcreteIterator。在ArrayList中的Iterator迭代器實現中,指的是Itr。
ArrayList程式碼片段
public class ArrayList<E>
{
/**
* 儲存新增到ArrayList中的元素。
* ArrayList的容量就是該陣列的長度。
* 該值為DEFAULTCAPACITY_EMPTY_ELEMENTDATA 時,當第一次新增元素進入ArrayList中時,陣列將擴容值DEFAULT_CAPACITY。
* 被標記為transient,在物件被序列化的時候不會被序列化。
*/
transient Object[] elementData;
// ArrayList的實際大小(陣列包含的元素個數)。
private int size;
/**
* 返回一個用來遍歷ArrayList元素的Iterator迭代器
*/
public Iterator<E> iterator() {
return new Itr();
}
/**
* AbstractList.Itr的最優化的版本
*/
private class Itr implements Iterator<E> {
int cursor; // 下一個要返回的元素的索引
int lastRet = -1; // 最近的被返回的元素的索引; 如果沒有返回-1。
int expectedModCount = modCount;
/**
* 判斷是否有下一個元素
*/
public boolean hasNext() {
//如果下一個要返回的元素的索引不等於ArrayList的實際大小,則返回false
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++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}
Iterator
import java.util.function.Consumer;
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
Itr.java
作為ArrayList的內部類。請在上文中的[ArrayList.java程式碼片段]中檢視。
ListIterator
ListIterator是一個更加強大的Iterator的子型別。它只能用於各種List類的訪問。它最大的優點是可以雙向移動。它還可以產生相對於迭代器在列表中指向的當前位置的前一個和後一個元素的索引,並且可以使用set()方法替換它訪問過的最後一個元素。
例子
在寫如何實現之前,先看一個使用列表迭代器ListIterator的小例子:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Test {
@org.junit.Test
public void test() {
List list = new ArrayList<>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
ListIterator iterator = list.listIterator();
System.out.println("--------------------向下遍歷--------------------");
while (iterator.hasNext()) {
int nextIndex = iterator.nextIndex();
String next = (String) iterator.next();
//int previousIndex = iterator.previousIndex();
System.out.println("當前元素:"+next+",當前元素索引:"+nextIndex/*+",前一個元素的索引"+previousIndex*/);
}
System.out.println("--------------------向上遍歷--------------------");
while (iterator.hasPrevious()) {
int previousIndex = iterator.previousIndex();
String previous = (String) iterator.previous();
System.out.println("當前元素:"+previous+",當前元素索引:"+previousIndex);
}
System.out.println("-----------測試set()和listIterator(n)----------");
System.out.println(list);
iterator = list.listIterator(3);
while(iterator.hasNext()){
iterator.next();
iterator.set("5");
}
System.out.println(list);
}
}
執行結果
-------向下遍歷-------
當前元素:0,當前元素索引:0
當前元素:1,當前元素索引:1
當前元素:2,當前元素索引:2
當前元素:3,當前元素索引:3
-------向上遍歷-------
當前元素:3,當前元素索引:3
當前元素:2,當前元素索引:2
當前元素:1,當前元素索引:1
當前元素:0,當前元素索引:0
-------測試set()和listIterator(n)-------
[0, 1, 2, 3]
[0, 1, 2, 5]
方法
- listIterator(),list.iterator()用來從容器物件中返回一個指向list開始處的迭代器。
- listIterator(n),list.iterator()用來從容器物件中返回一個指向列表索引為n的迭代器。
- next(),獲取序列中的下個元素,執行後索引+1。
- previous(),獲取序列中的上個元素,執行後索引-1。
- nextIndex,獲取序列中的下個元素的索引。
- previousIndex,獲取序列中的下個元素的索引。
- hasNext(),檢查序列中向下是否還有元素。
- hasPrevious(),檢查序列中向上是否還有元素。
- remove(),從列表中刪除next()或previous()返回的最後一個元素。這也意味著呼叫remove()前需要先呼叫next()或者previous()。
- add(E e): 將指定的元素插入列表,插入位置為迭代器當前位置之前。
- set(E e):從列表中將next()或previous()返回的最後一個元素返回的最後一個元素更改為指定元素e。
實現
在設計模式(16)-迭代器模式這一文章中曾講過,迭代器模式中有四個角色:
- 抽象聚合類Aggregate。在ArrayList的ListIterator迭代器實現中,沒有抽象聚合類。雖然它實現了AbstractList,實現了List,但它向外部提供的建立迭代器的方法listIterator()是它自己的。
- 具體聚合類ConcreteAggregate。在ArrayList的ListIterator迭代器實現中,指的是ArrayList。
- 抽象迭代器Iterator。在ArrayList的ListIterator迭代器實現中,指的是ListIterator。
- 具體迭代器ConcreteIterator。在ArrayList中的ListIterator迭代器實現中,指的是ListItr。
ArrayList程式碼片段
public class ArrayList<E>
{
/**
* 儲存新增到ArrayList中的元素。
* ArrayList的容量就是該陣列的長度。
* 該值為DEFAULTCAPACITY_EMPTY_ELEMENTDATA 時,當第一次新增元素進入ArrayList中時,陣列將擴容值DEFAULT_CAPACITY。
* 被標記為transient,在物件被序列化的時候不會被序列化。
*/
transient Object[] elementData;
// ArrayList的實際大小(陣列包含的元素個數)。
private int size;
/**
* 返回一個一開始就指向列表索引為index的元素處的ListIterator
*
* @throws IndexOutOfBoundsException
*/
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
/**
* 返回一個一開始就指向列表索引為0的元素處的ListIterator
*
* @see #listIterator(int)
*/
public ListIterator<E> listIterator() {
return new ListItr(0);
}
/**
* AbstractList.ListItr的最優化版本
*/
private class ListItr extends Itr implements ListIterator<E> {
//用來從list中返回一個指向list索引為index的元素處的迭代器
ListItr(int index) {
super();
cursor = index;
}
//獲取list中的上個元素
public boolean hasPrevious() {
return cursor != 0;
}
//獲取list中的下個元素的索引
public int nextIndex() {
return cursor;
}
//獲取list中的上個元素的索引
public int previousIndex() {
return cursor - 1;
}
//獲取list中的上個元素
@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];
}
//從列表中將next()或previous()返回的最後一個元素返回的最後一個元素更改為指定元素e
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();
}
}
}
}
Iterator
import java.util.function.Consumer;
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
ListItr.java
作為ArrayList的內部類。請在上文中的[ArrayList.java程式碼片段]中檢視。
總結
什麼是fail-fast?
細心地朋友看文章或原始碼時一定會發現在iterator()和listIterator()的註釋中都有一句話:返回的迭代器是fail-fast的。什麼是fail-fast?
好了,關於迭代器模式與ArrayList就寫到這裡。有什麼需要補充的歡迎在下方留言^^。