深入学习java源码之ArrayList.iterator()与ArrayList.listIterator()
内部类的使用典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外层类的对象。所以你可以认为内部类提供了某种进入其外层类的窗口。
使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外层类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
ArrayList<String> list = new ArrayList<String>();
list.add(null);
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
/*
* 使用迭代器遍历集合
*/
//获取迭代器
Iterator<String> it = list.iterator();
//使用while遍历集合
while(it.hasNext()){
String s = it.next();
/*
* 判断集合中有没有"abc3"这个元素
* 如果有,增加一个元素"itcast"
* 编程技巧:使用equals判断的时候,要把已知的变量写在前边,未知的写在后边,防止空指针异常
*/
//if(s.equals("abc3")){
if("abc3".equals(s)){
//1.迭代就是迭代,不要对集合进行修改
//list.add("itcast");
}
System.out.println(s);
}
/*
* 2.使用迭代器Iterator的子接口ListIterator中的方法add/remove,让迭代器自己增加往集合中增加元素/移除元素
*/
ListIterator<String> listIt = list.listIterator();
while(listIt.hasNext()){
String s = listIt.next();
if("abc3".equals(s)){
listIt.add("itcast");
}
System.out.println(s);
}
System.out.println(list);
}
集合类(包括List)现在都有一个forEach方法,对元素进行迭代(遍历),所以我们不需要再写for循环了。forEach方法接受一个函数接口Consumer做参数,所以可以使用λ表达式。
这种内部迭代方法广泛存在于各种语言,如C++的STL算法库、python、ruby、scala等。
for(Object o: list) { // 外部迭代
System.out.println(o);
}
可以写成:
list.forEach(o -> {System.out.println(o);}); //forEach函数实现内部迭代
java源码
一个集合的迭代器。 Iterator需要的地方Enumeration在Java集合框架。 迭代器有两种不同的枚举方式:
迭代器允许调用者在迭代期间从底层集合中删除元素,并具有明确定义的语义。
方法名称得到改进。
package java.util;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access
private int size;
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
public ListIterator<E> listIterator() {
return new ListItr(0);
}
public Iterator<E> iterator() {
return new Itr();
}
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;
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++]);
}
// 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();
}
}
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();
}
}
}
}
ConcurrentModificationException 异常
当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常。
例如,一个线程通常不允许修改集合,而另一个线程正在遍历它。 一般来说,在这种情况下,迭代的结果是未定义的。 某些迭代器实现(包括由JRE提供的所有通用集合实现的实现)可能会选择在检测到此行为时抛出此异常。 这样做的迭代器被称为故障快速迭代器,因为它们快速而干净地失败,而是在未来未确定的时间冒着任意的非确定性行为。
请注意,此异常并不总是表示对象已被不同的线程同时修改。 如果单个线程发出违反对象合同的方法调用序列,则该对象可能会抛出此异常。 例如,如果线程在使用故障快速迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。
请注意,故障快速行为无法保证,因为一般来说,在不同步并发修改的情况下,无法做出任何硬性保证。 失败快速的操作尽可能地抛出ConcurrentModificationException 。 因此,编写依赖于此异常的程序的正确性将是错误的: ConcurrentModificationException应仅用于检测错误。
package java.util;
public class ConcurrentModificationException extends RuntimeException {
private static final long serialVersionUID = -3666751008965953603L;
public ConcurrentModificationException() {
}
public ConcurrentModificationException(String message) {
super(message);
}
public ConcurrentModificationException(Throwable cause) {
super(cause);
}
public ConcurrentModificationException(String message, Throwable cause) {
super(message, cause);
}
}
Iterator
public interface Iterator<E>一个集合的迭代器。 Iterator需要的地方Enumeration在Java集合框架。 迭代器有两种不同的枚举方式:
迭代器允许调用者在迭代期间从底层集合中删除元素,并具有明确定义的语义。
方法名称得到改进。
此接口是成员Java Collections Framework 。
Modifier and Type |
Method and Description |
default void |
forEachRemaining(Consumer<? super E> action) 对每个剩余元素执行给定的操作,直到所有元素都被处理或动作引发异常。 |
boolean |
hasNext() 如果迭代具有更多元素,则返回 true 。 |
E |
next() 返回迭代中的下一个元素。 |
default void |
remove() 从底层集合中删除此迭代器返回的最后一个元素(可选操作)。 |
package java.util;
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());
}
}
ListIterator
用于允许程序员沿任一方向遍历列表的列表的迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置。 A ListIterator没有电流元素; 其光标位置始终位于通过调用previous()返回的元素和通过调用next()返回的元素next() 。 长度为n的列表的迭代器具有n+1可能的光标位置,如下图所示的^ ( ^ )所示:
Element(0) Element(1) Element(2) ... Element(n-1)
cursor positions: ^ ^ ^ ^ ^ 请注意, remove()和set(Object)方法未按光标位置进行定义; 它们被定义为对调用next()或previous()返回的最后一个元素进行操作。
package java.util;
public interface ListIterator<E> extends Iterator<E> {
// Query Operations
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
// Modification Operations
void remove();
void set(E e);
void add(E e);
}