ArrayDeque
ArrayDeque是基于数组实现的双端队列,常用于线程池中的工作队列需要是有界队列时使用的工作队列容器。
从源码描述中可知该容器不是线程安全的,在没有外部加锁的条件下,他们不能用于多线程下的并发访问。并且ArrayDeque中不允许向其中放入null元素。当该容器用做栈时他可能比Stack要高效一些。当该容器用作队列的时候他可能比LinkedList更高效一些。
声明
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable
{
//代码
}
继承自AbstractCollection,实现了Deque接口。
成员变量
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable
{
/**
* ArrayDeque内部基于数组实现的双端队列。双端队列的容量就是数组的长度。
* 该数组的长度总是2的n次方,并且不允许存在数组满的情况。
*/
transient Object[] elements; // non-private to simplify nested class access
/**
* 双端队列中的头元素,就是即将出队列(或者出栈)的那个元素。如果双端队列为空,那么,head=tail将可能是一个
* 任意的数字值。
*/
transient int head;
/**
* 下一个入队(进栈)元素应该存放的下标。
*/
transient int tail;
/**
* 一个新创建的双端队列的默认最小容量,必须是2的次方。
*/
private static final int MIN_INITIAL_CAPACITY = 8;
/**
* 用于支持序列化机制
*/
private static final long serialVersionUID = 2340985798034038923L;
}
构造方法——如何初始化
ArrayDeque提供了三种创建ArrayDeque的方式。分别是无参、给定初始容量、给定Collection实现类实例。从这里可以看出ArrayDeque一旦被创建,内部的数组实例就已经被初始化了。
/**
* 如果不穿任何参数,那么将构建一个初始容量为16的elements数组。
*/
public ArrayDeque()
{
elements = new Object[16];
}
/**
* 根据传入的numElements的值初始化elements数组
* 数组的容量是Math.max(MIN_INITIAL_CAPACITY = 8,第一个大于numElements的2的n次方)。
* 但是不要溢出了。
*/
public ArrayDeque(int numElements)
{
allocateElements(numElements);
}
/**
* 根据计算后的容量创建数组。
*/
private void allocateElements(int numElements)
{
elements = new Object[calculateSize(numElements)];
}
/**
* 该方法用于数组的分配和重新或者扩容的时候使用。
*/
private static int calculateSize(int numElements)
{
int initialCapacity = MIN_INITIAL_CAPACITY;
// 要寻找到第一个大于numElements的2的n次方。
if (numElements >= initialCapacity) {
initialCapacity = numElements;
initialCapacity |= (initialCapacity >>> 1);
initialCapacity |= (initialCapacity >>> 2);
initialCapacity |= (initialCapacity >>> 4);
initialCapacity |= (initialCapacity >>> 8);
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
//元素值太大了,溢出了。需要减半。如果要分类2的三十次方个元素,那么
//由于要查找大于该数的2的次方那就是2的三十一次方,这已经超过了int类型所能表示的最大范围。
if (initialCapacity < 0) // Too many elements, must back off
initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
}
return initialCapacity;
}
/**
* 根据Collection实现类c中的所有元素创建elements数组。并将其中的元素全部添加至deque中。
* 顺序与c中迭代器返回的顺序一致。
*/
public ArrayDeque(Collection<? extends E> c)
{
allocateElements(c.size());
addAll(c);
}
常用方法
添加元素
addFirst方法
/**
* 添加元素e到deque的最前面。如果e为空,则抛出NullPointerException。
*/
public void addFirst(E e)
{
if (e == null)
throw new NullPointerException();
//由于要插入到最前面,那就是head-1。
elements[head = (head - 1) & (elements.length - 1)] = e;
//这个时候,数组中的元素已经满了,没有可用空间了,将数组容量翻倍。
if (head == tail)
doubleCapacity();
}
/**
* 将双端队列中的数组扩容为原来的两倍。只有当数组满的时候才会执行此操作,并且head==tail是。
* 因为ArrayDeque中的数组是循环使用的。当tail追上了head说明数组处于满的状态了。
*/
private void doubleCapacity()
{
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // number of elements to the right of p
int newCapacity = n << 1;
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
Object[] a = new Object[newCapacity];
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = a;
head = 0;
tail = n;
}
/**
* 将元素添加到栈顶,也就是队列的头部。该方法使用addFirst实现。
*/
public void push(E e)
{
addFirst(e);
}
offerFirst方法
/**
* 将元素入队列到队列的最前面的元素。该方法与addFirst一样,只不过该方法添加成功返回true。
*/
public boolean offerFirst(E e)
{
addFirst(e);
return true;
}
addLast方法
/**
* 添加元素e到deque的最后面。如果e为空,则抛出NullPointerException。
*/
public void addLast(E e)
{
if (e == null)
throw new NullPointerException();
//tail位置就是下一个将要从后面入队的元素。
elements[tail] = e;
//这时候队列已经满了,内部的数组已经没有空间了。马上扩容。
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}
offerLast方法
/**
* 将元素入队列到队列的最后面的元素。该方法与addLast一样,只不过该方法添加成功返回true。
*/
public boolean offerLast(E e)
{
addLast(e);
return true;
}
add方法
/**
* 将元素添加到队列的尾部,使用addLast实现,新瓶装旧酒。
*/
public boolean add(E e)
{
addLast(e);
return true;
}
offer方法
/**
* 将元素添加到队列的尾部,使用offerLast实现,新瓶装旧酒。
*/
public boolean offer(E e)
{
return offerLast(e);
}
删除元素
pollFirst方法
/**
* 将head处元素出队列并返回该元素,并将head处的元素置为空。
* 这里可以理解为什么ArrayDeque不能存放null元素了。因为这样就
* 不能区分一个位置是空闲的还是存放了null元素。
* 另外这里的取模操作也转化为与数组长度相与的操作,这里数组的长度必须是2的n次方才可以
* 这样代替取模操作。
*/
public E pollFirst()
{
int h = head;
@SuppressWarnings("unchecked")
E result = (E) elements[h];
// 如果队列为空,则返回null.
if (result == null)
return null;
elements[h] = null; // Must null out slot
head = (h + 1) & (elements.length - 1);
return result;
}
poll方法
/**
* 将队列中最前面的元素出队并且返回元素。使用pollFirst实现。
*/
public E poll()
{
return pollFirst();
}
pollLastf方法
/**
* 将tail-1处元素出队列并返回该元素,并将tail-1处的元素置为空。
* 这里可以理解为什么ArrayDeque不能存放null元素了。因为这样就
* 不能区分一个位置是空闲的还是存放了null元素。
* 另外这里的取模操作也转化为与数组长度相与的操作,这里数组的长度必须是2的n次方才可以
* 这样代替取模操作。
*/
public E pollLast()
{
//tail是下一个要从尾部加入的元素的位置。所以tail-1才是最后一个元素的位置。
int t = (tail - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[t];
if (result == null)
return null;
elements[t] = null;
tail = t;
return result;
}
removeFirst方法
/**
* 将队列中最前面的元素出队并且返回元素。该方法与pollFirst基本一致,只不过当元素为空时该方法
* 将抛出NoSuchElementException
*/
public E removeFirst()
{
E x = pollFirst();
if (x == null)
throw new NoSuchElementException();
return x;
}
remove方法
/**
* 将队列中最前面的元素出队并且返回元素。使用removeFirst实现。
*/
public E remove()
{
return removeFirst();
}
/**
* 将栈顶元素删除并弹出返回,也就是删除并返回头部的元素。使用removeFirst实现。
*/
public E pop() {
return removeFirst();
}
removeLast方法
/**
* 将队列中最后面的元素出队并且返回元素。该方法与pollLast基本一致,只不过当元素为空时该方法
* 将抛出NoSuchElementException
*/
public E removeLast()
{
E x = pollLast();
if (x == null)
throw new NoSuchElementException();
return x;
}
delete方法
/**
* 删除数组中特定元素的的下标位置处的元素。这将导致head以及tail的调整,
* 同时会有一部分元素想前或者向后移动。
* 向前移动的情况很好理解,数组正常的head<tail的时候,删除元素会导致后面的元素前移。
* 向后移动元素则是head>tail的时候,如果删除了尾部的元素。那么将导致前面的元素虽然在位置上是排在前面的但是
* 在队列中是排在后面的,所以要向后移动。
*/
private boolean delete(int i)
{
checkInvariants();
final Object[] elements = this.elements;
final int mask = elements.length - 1;
final int h = head;
final int t = tail;
final int front = (i - h) & mask;
final int back = (t - i) & mask;
// 这个i不在head到tail管辖的范围之内。
if (front >= ((t - h) & mask))
throw new ConcurrentModificationException();
//寻找移动元素数量最少的方法。前移还是后移。
// front和back表示要删除的元素离head更近还是离tail更近。
//这种情况是离head更近。
if (front < back)
{
// 0 0 x 0 0 0 0 0 0
// h t
//这种情况是head在前,tail在后,并且要删除的元素离head更近
if (h <= i)
{
//前面的元素后移一位。
System.arraycopy(elements, h, elements, h + 1, front);
}
else
{ // Wrap around
// 0 0 0 0 0 0 0 0 0
// t x h
//这种情况是这种情况是head在后,tail在前,并且要删除的元素离head更近,并且x在h的前面。
//那么首先将x之前的元素后移,然后让最后的元素前移到0位置。
//然后将h处的元素后移一位。
//这种方式是循环后移。
System.arraycopy(elements, 0, elements, 1, i);
elements[0] = elements[mask];
System.arraycopy(elements, h, elements, h + 1, mask - h);
}
elements[h] = null;
head = (h + 1) & mask;
return false;
}
//这种情况是离tail更近。
else
{
//如果要删除的元素在tail的前面
// 0 0 0 0 0 0 0 0 0
// h x t
if (i < t)
{ // Copy the null tail as well
//把x之后的元素到tail之前的元素前移即可了。
System.arraycopy(elements, i + 1, elements, i, back);
tail = t - 1;
}
//如果要删除的元素在tail的后面
// 0 0 0 0 0 0 0 0 0 0 0
// t h x
else
{ // Wrap around
//那么将x后面的元素前移一位
//然后将0处的元素移到末尾。
//然后将从1开始到t之前的元素前移一位。
//这种方式是循环前移。
System.arraycopy(elements, i + 1, elements, i, mask - i);
elements[mask] = elements[0];
System.arraycopy(elements, 1, elements, 0, t);
tail = (t - 1) & mask;
}
return true;
}
}
/**
* 检查项:
* 1、tail处必须为null。
* 2、队列为空或者队列至少有一个元素且队列不满。
*/
private void checkInvariants()
{
assert elements[tail] == null;
assert head == tail ? elements[head] == null :
(elements[head] != null &&
elements[(tail - 1) & (elements.length - 1)] != null);
assert elements[(head - 1) & (elements.length - 1)] == null;
}
removeFirstOccurrence方法
/**
* 从head(第一个元素开始向后遍历)直到找到与传入o相等的元素并根据此时的下标删除该元素。
* 删除的逻辑委托为内部的delete方法实现。
* 如果传入的元素o为null,直接不做任何操作返回false。
* 如果没有找到与之相匹配的也返回false。
*/
public boolean removeFirstOccurrence(Object o)
{
if (o == null)
return false;
int mask = elements.length - 1;
int i = head;
Object x;
while ( (x = elements[i]) != null)
{
if (o.equals(x))
{
delete(i);
return true;
}
i = (i + 1) & mask;
}
return false;
}
remove方法
/**
* 从head(第一个元素开始向后遍历)直到找到与传入o相等的元素并根据此时的下标删除该元素。
* 删除的逻辑委托为内部的removeFirstOccurrence方法实现。
* 如果传入的元素o为null,直接不做任何操作返回false。
* 如果没有找到与之相匹配的也返回false。
*/
public boolean remove(Object o) {
return removeFirstOccurrence(o);
}
removeLastOccurrence方法
/**
* 从tail-1(最后一个元素开始向前遍历)直到找到与传入o相等的元素并根据此时的下标删除该元素。
* 删除的逻辑委托为内部的delete方法实现。
* 如果传入的元素o为null,直接不做任何操作返回false。
* 如果没有找到与之相匹配的也返回false。
*/
public boolean removeLastOccurrence(Object o)
{
if (o == null)
return false;
int mask = elements.length - 1;
int i = (tail - 1) & mask;
Object x;
while ( (x = elements[i]) != null)
{
if (o.equals(x))
{
delete(i);
return true;
}
i = (i - 1) & mask;
}
return false;
}
/**
* 删除队列中的所有的元素,该方法返回后队列将变为空。
*/
public void clear()
{
int h = head;
int t = tail;
if (h != t)
{ // clear all cells
head = tail = 0;
int i = h;
int mask = elements.length - 1;
do {
elements[i] = null;
i = (i + 1) & mask;
} while (i != t);
}
}
获取元素
getFirst方法
/**
* 只是获取head处的元素的值。不对队列做操作。如果对应处元素为null,则抛出异常
*/
public E getFirst()
{
@SuppressWarnings("unchecked")
E result = (E) elements[head];
if (result == null)
throw new NoSuchElementException();
return result;
}
element方法
/**
* 只是获取head处的元素的值。不对队列做操作。如果对应处元素为null,则抛出异常
* 该方法与getFirst,peek,peekFirst方法类似,但是peek系的方法不会抛出异常。
*/
public E element()
{
return getFirst();
}
getLast方法
/**
* 只是获取tail-1处的元素的值。不对队列做操作。如果对应处元素为null,则抛出异常
*/
public E getLast()
{
@SuppressWarnings("unchecked")
E result = (E) elements[(tail - 1) & (elements.length - 1)];
if (result == null)
throw new NoSuchElementException();
return result;
}
peekFirst方法
/**
* 只是获取head处的元素的值。不对队列做操作。如果队列为空,则返回null。
*/
@SuppressWarnings("unchecked")
public E peekFirst()
{
// elements[head] is null if deque empty
return (E) elements[head];
}
/**
* 只是获取head处的元素的值。不对队列做操作。如果队列为空,则返回null。该方法使用peekFirst实现。
*/
public E peek()
{
return peekFirst();
}
peekLast方法
/**
* 只是获取tail-1处的元素的值。不对队列做操作。如果队列为空,则返回null。
*/
@SuppressWarnings("unchecked")
public E peekLast()
{
return (E) elements[(tail - 1) & (elements.length - 1)];
}
查询信息
size方法
/**
* 返回队列中的元素的数量。
* 一个负数与一个2的n次方-1相与相当于2的n次方减(这个负数的绝对值然后取模2的n次方)。
*/
public int size()
{
return (tail - head) & (elements.length - 1);
}
isEmpty方法
/**
* 查看队列是否为空,当head与tail相同时为空。
*/
public boolean isEmpty()
{
return head == tail;
}
contains方法
/**
* 如果队列中从head到tail包含该元素o,则返回true,否则返回false。
* 注意如果传入的元素为null,那么直接返回false。
*/
public boolean contains(Object o)
{
if (o == null)
return false;
int mask = elements.length - 1;
int i = head;
Object x;
while ( (x = elements[i]) != null)
{
if (o.equals(x))
return true;
i = (i + 1) & mask;
}
return false;
}
ArrayDeque内部的迭代器实现
获取迭代器
iterator方法
/**
* 获取ArrayDeque实现的Iterator实现类DeqIterator的实例。用于
* 遍历元素。元素的顺序是从head到tail的顺序。
* 该顺序与元素出队列的顺序一致。
*/
public Iterator<E> iterator()
{
return new DeqIterator();
}
descendingIterator方法
/**
* 获取ArrayDeque实现的Iterator实现类DescendingIterator的实例。用于
* 遍历元素。元素的顺序是从tail-1到head的顺序。
* 该顺序与元素出队列的顺序相反。
*/
public Iterator<E> descendingIterator()
{
return new DescendingIterator();
}
Iterator实现类——DeqIterator
private class DeqIterator implements Iterator<E>
{
/**
* 下一个调用next方法应该返回的元素的位置。
*/
private int cursor = head;
/**
* tail用来停止迭代器,因为遍历到tail也就代表达到了队列的尾部。
* 同时tail在这里充当了modCount的角色。但是相比起modCount来
* 这个变量要逊色很多,他并不能检测到任何可能的篡改,只能规范遍历的规则。
*/
private int fence = tail;
/**
* 上次调用next方法返回的元素的元素的位置,如何调用了remove方法,那么
* 该方法将被置为-1,以拒绝后续的remove操作。
*/
private int lastRet = -1;
public boolean hasNext()
{
return cursor != fence;
}
public E next()
{
if (cursor == fence)
throw new NoSuchElementException();
@SuppressWarnings("unchecked")
E result = (E) elements[cursor];
// This check doesn't catch all possible comodifications,
// but does catch the ones that corrupt traversal
if (tail != fence || result == null)
throw new ConcurrentModificationException();
lastRet = cursor;
cursor = (cursor + 1) & (elements.length - 1);
return result;
}
//该方法内部是通过delete方法删除lastRet位置的元素。
public void remove()
{
if (lastRet < 0)
throw new IllegalStateException();
if (delete(lastRet))
{ // 返回true代表删除操作是通过循环左移的。
cursor = (cursor - 1) & (elements.length - 1);
fence = tail;
}
lastRet = -1;
//后续不能再次马上调用remove方法了。
}
//从cursor到fence处的元素将交给Consumer来消费。
public void forEachRemaining(Consumer<? super E> action)
{
Objects.requireNonNull(action);
Object[] a = elements;
int m = a.length - 1, f = fence, i = cursor;
cursor = f;
while (i != f)
{
@SuppressWarnings("unchecked") E e = (E)a[i];
i = (i + 1) & m;
if (e == null)
throw new ConcurrentModificationException();
action.accept(e);
}
}
}
Iterator实现类——DescendingIterator
private class DescendingIterator implements Iterator<E>
{
/*
* 该类几乎是DeqIterator的镜像类。使用tail来作为初始的cursor,使用head来作为fence.
*/
private int cursor = tail;
private int fence = head;
private int lastRet = -1;
public boolean hasNext()
{
return cursor != fence;
}
//这个时候cursor要递减。
public E next()
{
if (cursor == fence)
throw new NoSuchElementException();
cursor = (cursor - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[cursor];
if (head != fence || result == null)
throw new ConcurrentModificationException();
lastRet = cursor;
return result;
}
public void remove()
{
if (lastRet < 0)
throw new IllegalStateException();
if (!delete(lastRet))
{
//返回false是代表循环后移的。
cursor = (cursor + 1) & (elements.length - 1);
fence = head;
}
lastRet = -1;
}
}
ArrayDeque内部的序列化规则
writeObject方法
/**
* 保存当前队列到流中。
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
{
s.defaultWriteObject();
// Write out size
s.writeInt(size());
// Write out elements in order.
int mask = elements.length - 1;
for (int i = head; i != tail; i = (i + 1) & mask)
s.writeObject(elements[i]);
}
其他方法
copyElements方法
/**
* 将Deque内部的数组中的元素复制到给定的数组a中,这里并没有检查数组a是否可以容纳下队列
* 中的所有的元素,而是假设可以容纳。因为该方法是private的,只能内部使用。
* 如果head<tail的情况,那么数组中的元素就是[head,tail)。直接复制就可以了
* 如果head>tail,那么就需要复制两次。一次是[head,elements.length-1]。
* 另一次是[0,tail)。
*/
private <T> T[] copyElements(T[] a)
{
if (head < tail)
{
System.arraycopy(elements, head, a, 0, size());
}
else if (head > tail)
{
int headPortionLen = elements.length - head;
System.arraycopy(elements, head, a, 0, headPortionLen);
System.arraycopy(elements, 0, a, headPortionLen, tail);
}
return a;
}
/**
* 该方法首先创建一个当前队列中元素数量大小的数组,然后将队列中的元素复制到数组中,,由于是新创建的数组
* 因为返回给调用者之后,调用者可以随意的修改。但是
* 该复制也还是浅复制,就是如何修改内部元素的属性,还是会反映到队列内部。
*/
public Object[] toArray()
{
return copyElements(new Object[size()]);
}
/**
* 该方法通过传入一个泛型类型的数组,如果队列中的元素数量小于传入的数组的容量,那么
* 就将队列中的元素复制到传入的数组中,此时如果数组中还有剩余空间,那么数组中第size(队列中的元素的数量)
* 设置为null,以供调用者区分(前提是调用者确定集合中不存在非空元素)。
* 如果传入的数组不能装下队列中的所有元素,那么就新创建一个与传入数组相同类型的新数组,容量为size。
*并将队列中的元素复制到新数组中返回。
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a)
{
int size = size();
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
copyElements(a);
if (a.length > size)
a[size] = null;
return a;
}
/**
* 返回当前队列的一个拷贝,这个拷贝是浅拷贝。
*/
public ArrayDeque<E> clone()
{
try
{
@SuppressWarnings("unchecked")
ArrayDeque<E> result = (ArrayDeque<E>) super.clone();
result.elements = Arrays.copyOf(elements, elements.length);
return result;
}
catch (CloneNotSupportedException e)
{
throw new AssertionError();
}
}
readObject方法
/**
* 从流中重建队列。
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException
{
s.defaultReadObject();
// Read in size and allocate array
int size = s.readInt();
int capacity = calculateSize(size);
SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
allocateElements(size);
head = 0;
tail = size;
// Read in all elements in the proper order.
for (int i = 0; i < size; i++)
elements[i] = s.readObject();
}
java8新增api
/**
* Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
* and <em>fail-fast</em> {@link Spliterator} over the elements in this
* deque.
*
* <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
* {@link Spliterator#NONNULL}. Overriding implementations should document
* the reporting of additional characteristic values.
*
* @return a {@code Spliterator} over the elements in this deque
* @since 1.8
*/
public Spliterator<E> spliterator()
{
return new DeqSpliterator<E>(this, -1, -1);
}
static final class DeqSpliterator<E> implements Spliterator<E>
{
private final ArrayDeque<E> deq;
private int fence; // -1 until first use
private int index; // current index, modified on traverse/split
/** Creates new spliterator covering the given array and range */
DeqSpliterator(ArrayDeque<E> deq, int origin, int fence)
{
this.deq = deq;
this.index = origin;
this.fence = fence;
}
private int getFence()
{ // force initialization
int t;
if ((t = fence) < 0)
{
t = fence = deq.tail;
index = deq.head;
}
return t;
}
public DeqSpliterator<E> trySplit()
{
int t = getFence(), h = index, n = deq.elements.length;
if (h != t && ((h + 1) & (n - 1)) != t)
{
if (h > t)
t += n;
int m = ((h + t) >>> 1) & (n - 1);
return new DeqSpliterator<>(deq, h, index = m);
}
return null;
}
public void forEachRemaining(Consumer<? super E> consumer)
{
if (consumer == null)
throw new NullPointerException();
Object[] a = deq.elements;
int m = a.length - 1, f = getFence(), i = index;
index = f;
while (i != f)
{
@SuppressWarnings("unchecked") E e = (E)a[i];
i = (i + 1) & m;
if (e == null)
throw new ConcurrentModificationException();
consumer.accept(e);
}
}
public boolean tryAdvance(Consumer<? super E> consumer)
{
if (consumer == null)
throw new NullPointerException();
Object[] a = deq.elements;
int m = a.length - 1, f = getFence(), i = index;
if (i != fence)
{
@SuppressWarnings("unchecked") E e = (E)a[i];
index = (i + 1) & m;
if (e == null)
throw new ConcurrentModificationException();
consumer.accept(e);
return true;
}
return false;
}
public long estimateSize()
{
int n = getFence() - index;
if (n < 0)
n += deq.elements.length;
return (long) n;
}
@Override
public int characteristics()
{
return Spliterator.ORDERED | Spliterator.SIZED |
Spliterator.NONNULL | Spliterator.SUBSIZED;
}
}
几个注意
- 所有的remove相关的api都会抛出异常(NoSuchElementException),而poll相关api在队列为空时将返回null。
- 所有的get相关的api都可能会抛出异常(NoSuchElementException),而peek相关api在队列为空时返回null。
- ArrayDeque是双端队列,因此前后都可以操作数组,而ArrayDeque对于栈的相关api的实现是通过操作队列最前面的数据元素实现的。并且相关的出栈操作使用的相应的remove相关api,也就是可能会抛出相关异常。
- 除了创建时刻会初始化数组,队列中只有addFirst和addLast方法会引起队列内部数组容量的翻倍。翻倍的条件是head==tail