LinkedList底层是使用双向链表实现的,他实现了List接口和Deque接口(该接口继承自Queue接口),所以LinkedList可以被安全的转为Deque和Queue。实际上她现在也是使用Deque与Queue的推荐实现。LinkedList中可以存放任何引用类型的元素。包括null。
声明
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
//代码
}
该类继承自AbstractSequentialList,这个可以标识LinkedList只能支持顺序访问,不能像ArrayList那样支持随机访问。
成员变量
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
//表示linkedList中存放的元素的数字
transient int size = 0;
/**
* 用于定位首节点。
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* 用于定位尾节点。
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
//用于序列化
private static final long serialVersionUID = 876323262645176354L;
}
LinkedList内部使用Node来作为链表节点存放我们放入其中的元素的。
存放元素的盒子——Node
Node节点是LinkedList实现双向链表的关键,它是在LinkedList内部以私有内部类的形式定义供LinkedList的API使用,Node的定义还是挺简单的,就是实现双向链表的最基本的元素节点。
private static class Node<E>
{
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next)
{
this.item = element;
this.next = next;
this.prev = prev;
}
}
构造方法——如何初始化
/**
* 无参数的构造方法,可以看到没有进行任何的动作。
*/
public LinkedList()
{
}
/**
* 将Collection实现类的实例c中的元素使用LinkedList的addAll方法添加到内部的双向链表中。
*/
public LinkedList(Collection<? extends E> c)
{
this();
addAll(c);
}
LinkedList提供两个构造方法来初始化。
常用方法
获取元素
getFirst方法
/**
* 该方法用于返回链表头指针所指向的结点的元素。如果链表为空,那么将抛出异常。
*/
public E getFirst()
{
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
getLast方法
/**
* 该方法用于返回链表尾指针所指向的结点的元素。如果链表为空,那么将抛出异常。
*/
public E getLast()
{
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
get方法
/**
* 返回指定下标处的结点内部的item中存放的值,由于链表的特性,该方法的时间复杂度为O(n)。
* 该方法内部通过node方法定位指定下标元素。该方法首先要检查下标是否合理。合理的范围是[0,size-1]
* 如何不合理将抛出 IndexOutOfBoundsException异常。
*/
public E get(int index)
{
checkElementIndex(index);
return node(index).item;
}
private void checkElementIndex(int index)
{
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* 修改或者获取元素是的下标检查。
*/
private boolean isElementIndex(int index)
{
return index >= 0 && index < size;
}
peek方法
/**
* 返回链表的头指针指向的元素,如果链表为空返回null,但不删除。
*/
public E peek()
{
final Node<E> f = first;
return (f == null) ? null : f.item;
}
peekFirst方法
/**
* 返回链表的头指针指向的元素,如果链表为空返回null,但不删除。该方法与peek方法实现完全一致。
*/
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
peekLast方法
/**
* 返回链表的尾指针指向的元素,如果链表为空返回null,但不删除。
*/
public E peekLast()
{
final Node<E> l = last;
return (l == null) ? null : l.item;
}
element方法
/**
* 该方法与peek方法基本一致。该方法适用getFirst获取头指针指向的结点内的item值。
* 不同的是,如果链表为空,该方法将抛出异常。
*/
public E element()
{
return getFirst();
}
getFirst方法
/**
* 返回头指针指向的结点内的item值。如果链表为空,则抛出NoSuchElementException。
*/
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
删除元素
remove方法
/**
* 从头结点开始寻找,判断节点内部的item是否与传入的0相等,或者为null(o为null)。
* 如果找到,则使用unlink方法删除该节点,并返回true。
* 如果没有找到,链表不做修改,返回false。
*/
public boolean remove(Object o)
{
if (o == null) {
for (Node<E> x = first; x != null; x = x.next)
{
if (x.item == null)
{
unlink(x);
return true;
}
}
}
else
{
for (Node<E> x = first; x != null; x = x.next)
{
if (o.equals(x.item))
{
unlink(x);
return true;
}
}
}
return false;
}
/**
* 将节点x从链表中移除,要求x不能为空。
*/
E unlink(Node<E> x)
{
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null)
{
first = next;
}
else
{
prev.next = next;
x.prev = null;
}
if (next == null)
{
last = prev;
}
else
{
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
/**
* 不带任何参数的remove方法将于removeFirst相同,删除链表的头指针所指向的元素。
*/
public E remove()
{
return removeFirst();
}
poll方法
/**
* 删除并返回头指针指向的元素。该方法内部使用unlinkFirst操作。只不过如何连表为空返回null
*/
public E poll()
{
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
pop方法
/**
* 弹出栈顶元素,也就是链表的首节点所指向的元素,如果链表为空那么将抛出异常。
*/
public E pop()
{
return removeFirst();
}
removeFirst方法
/**
* 删除并返回链表头指针所指向的结点的元素,如果链表为空则抛出异常。该方法使用unlinkFirst方法删除头结点的元素。
* 可以确保传入unlinkFirst的头结点不为空
*/
public E removeFirst()
{
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
/**
* 将头指针指向的头结点从链表中移除。要求f必须不为null,并且f是当前链表的头结点。
*/
private E unlinkFirst(Node<E> f)
{
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC,这里不用设置prev因为,f为头结点,其prev本身为null
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
removeFirstOccurrence方法
/**
* 从头指针指向的结点开始向后遍历,找到第一个与o相等或者等于null(o为null)的元素,将其删除。如果删除成功返回true。
* 如果没有周到返回false。
*/
public boolean removeFirstOccurrence(Object o)
{
return remove(o);
}
removeLastOccurrence方法
/**
* 从尾指针指向的结点开始向前遍历,找到第一个与o相等或者等于null(o为null)的元素,将其删除。如果删除成功返回true。
* 如果没有周到返回false。
*/
public boolean removeLastOccurrence(Object o)
{
if (o == null)
{
for (Node<E> x = last; x != null; x = x.prev)
{
if (x.item == null)
{
unlink(x);
return true;
}
}
}
else
{
for (Node<E> x = last; x != null; x = x.prev)
{
if (o.equals(x.item))
{
unlink(x);
return true;
}
}
}
return false;
}
pollFirst方法
/**
* 删除并返回头指针指向的元素。该方法内部使用unlinkFirst操作。该方法与poll方法完全一致。
*/
public E pollFirst()
{
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
removeLast方法
/**
* 删除并返回链表尾指针所指向的结点的元素,如果链表为空则抛出异常。该方法使用unlinkLast方法删除尾结点的元素。
* 可以确保传入unlinkLast的尾结点不为空
*/
public E removeLast()
{
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
/**
* 将尾指针指向的尾结点从链表中移除。要求f必须不为null,并且f是当前链表的尾结点。
*/
private E unlinkLast(Node<E> l)
{
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC 这里不用设置next因为,f为尾结点,其next本身为null
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
pollLast方法
/**
* 删除并返回链表尾指针指向的结点内的元素,如果链表为空,则返回null,这个与removeLast区分。
*/
public E pollLast()
{
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
clear方法
/**
* 删除集合链表中的所有的元素,该方法执行完成后。链表将为空。
* 最后还有置空头指针和尾指针。
*/
public void clear()
{
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
for (Node<E> x = first; x != null; )
{
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
添加元素
add方法
/**
* 该方法将元素添加到链表的尾部,该方法与addLast逻辑完全一致,只不过该方法会返回true.
*/
public boolean add(E e)
{
linkLast(e);
return true;
}
/**
* 将元素放到到链表的最后面,使之成为尾节点。
*/
void linkLast(E e)
{
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
//添加之前,链表是空的状态
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
offer方法
/**
* 添加元素e到链表的尾部。该方法与add方法作用一致。
*/
public boolean offer(E e)
{
return add(e);
}
push方法
/**
* 将元素e加入到链表的头部。
*/
public void push(E e)
{
addFirst(e);
}
addAll方法
/**
* 将Collection实现类实例c中的所有元素添加到该linkedList内部的链表中。
* 注意是添加到内部链表的尾部。如果在添加的过程中c中元素有修改的话那么可能导致
* 结果的不可预知性。
* 该方法使用带参数的addAll方法插入到链表的最后的位置。
*/
public boolean addAll(Collection<? extends E> c)
{
return addAll(size, c);
}
/**
* 将Collection实现类c中的所有元素插入到指定的index位置。并将[index,size-1]位置的所有元素
* 后移,当然这里相比ArrayList实现要轻量许多,只需要改动一处的指针就可以实现这些元素的后移。
* 1、检查传入的index是否合理,合理的范围是[0,size]。通过 checkPositionIndex实现。如果
* 不在该范围内,将抛出IndexOutOfBoundsException。
* 2、将集合中的元素得到其拷贝数组的形式。该方法执行过后c中的修改将对该集合链表没有影响了。
* 该方法执行前或者执行中都可能对该方法的执行产生影响。
* 3、通过node方法定位到index位置处的元素节点。并记录该节点为succ,它的前驱节点为pred。
* 4、将c中的元素构造成Node节点依次添加到pred的后面。最后将pred.next指向原来index位置的结点。
* 我们用succ保存了下来。
* 5、注意如果pred或者succ为null的情况要同时更新头指针和尾指针。
* 6、如果添加成功,则返回true,如果c中不包含元素那么返回false。
*/
public boolean addAll(int index, Collection<? extends E> c)
{
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size)
{
succ = null;
pred = last;
}
else
{
succ = node(index);
pred = succ.prev;
}
for (Object o : a)
{
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null)
{
last = pred;
}
else
{
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
/**
* 检查要插入的index位置是否合理。合理的返回是[0,size],该方法通过isPositionIndex(index)返回的
* boolean类型的值判断。这些方法只能内部使用。
*/
private void checkPositionIndex(int index)
{
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isPositionIndex(int index)
{
return index >= 0 && index <= size;
}
/**
* 该方法返回当检查插入index不合理是返回的错误信息。
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
/**
* 返回下标在index处的结点。
* 该方法进行了一定的优化,如果index<=size(链表中元素数量),那么使用头结点遍历寻找
* 否则使用尾结点遍历寻找。
* 由于链表不支持随机访问,因此该方法不能像ArrayList中以常数时间复杂度取得。
*/
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1))
{
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
}
else
{
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
addFirst方法
/**
* 将元素e添加至链表的最前面,使用linkFirst添加。
*/
public void addFirst(E e)
{
linkFirst(e);
}
/**
* 将元素放到到链表的最前面,使之成为首节点。该方法为private,只能供LinkedList内部使用
*/
private void linkFirst(E e)
{
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
//当前链表为空,那么尾指针也指向该节点。因为该节点是唯一的结点。
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
offerFirst方法
/**
* 将元素e添加到链表的最前面。使用addFirst完成。
*/
public boolean offerFirst(E e)
{
addFirst(e);
return true;
}
addLast方法
/**
* 将元素e添加至链表的最后面,使用linkLast添加。
*/
public void addLast(E e)
{
linkLast(e);
}
offerLast方法
/**
* 添加元素e到链表的尾部,使用addLast方法完成。
*/
public boolean offerLast(E e)
{
addLast(e);
return true;
}
链表信息类
size方法
/**
* 返回链表中存放了多少个元素。该方法直接返回内部的成员变量size,是常数级的。
*/
public int size()
{
return size;
}
查询元素
indexOf方法
/**
* 从链表的头结点开始遍历,如果要查询的元素为null,那么就从头结点查找第一个结点中存放的元素(item)为
* null的结点,找到返回其下标。
* 如果要查询的元素不为null,那么从头结点使用equals方法遍历链表中的结点内部的item是否与之相等。
* 找到返回其下标。
* 如果都没有赵到,返回-1。
*/
public int indexOf(Object o)
{
int index = 0;
if (o == null)
{
for (Node<E> x = first; x != null; x = x.next)
{
if (x.item == null)
return index;
index++;
}
}
else
{
for (Node<E> x = first; x != null; x = x.next)
{
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
lastIndexOf方法
/**
* 该方法使用尾结点从链表的尾部开始遍历寻找与o相等或者等于null(o=null)的结点的下标值。
* 如果找到返回其下标,否则返回-1。
*/
public int lastIndexOf(Object o)
{
int index = size;
if (o == null)
{
for (Node<E> x = last; x != null; x = x.prev)
{
index--;
if (x.item == null)
return index;
}
}
else
{
for (Node<E> x = last; x != null; x = x.prev)
{
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
contains方法
/**
* 判断linkedList的链表中是否包含指定的元素,该方法借助indexOf完成,如果返回-1,那么说明不包含。返回false.
* 否则返回true。
*/
public boolean contains(Object o)
{
return indexOf(o) != -1;
}
设置元素
set方法
/**
* 替换指定位置处的元素节点内的item。该方法并不新建一个节点,而只是替换节点内部的item信息。
* 首先要检查传入的index是否合理,合理的范围值[0,size-1]。
* 如果通过了检查那么将通过node方法定位index处节点。然后修改该节点的item信息。
*/
public E set(int index, E element)
{
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
LinkedList内部的迭代器实现
获取迭代器
/**
* 该方法将返回一个ListIterator<E>实现类,指定的index可以从链表的任意位置遍历
* 首先要检查传入的index的合理性。合理的范围是[0,size],注意size也可以,但是不会遍历
* 到任何的元素。这个list-iterator也是支持fail-fast机制的。
*/
public ListIterator<E> listIterator(int index)
{
checkPositionIndex(index);
return new ListItr(index);
}
/**
* 该方法将返回一个Iterator的实现类用于倒序的遍历集合中的元素。
*/
public Iterator<E> descendingIterator()
{
return new DescendingIterator();
}
LinkedList的ListIterator内部实现
private class ListItr implements ListIterator<E>
{
private Node<E> lastReturned;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount;
ListItr(int index)
{
// 如何传入size,将不会遍历到任何元素,
//否则使用node定位节点。
next = (index == size) ? null : node(index);
nextIndex = index;
}
public boolean hasNext()
{
return nextIndex < size;
}
public E next()
{
//检查是否在迭代器创建了之后,除了通过迭代器本身是否进行了结构化修改。如何是,马上抛出异常
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
public boolean hasPrevious()
{
return nextIndex > 0;
}
public E previous()
{
//检查是否在迭代器创建了之后,除了通过迭代器本身是否进行了结构化修改。如何是,马上抛出异常
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
public int nextIndex()
{
return nextIndex;
}
public int previousIndex()
{
return nextIndex - 1;
}
public void remove()
{
checkForComodification();
//还没有遍历任何的元素,此时也不知道该删除谁。
if (lastReturned == null)
throw new IllegalStateException();
//要删除的元素是lastReturned节点。
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
//保证下次遍历的是删除的结点的下一结点。
nextIndex--;
//从这里可以看出不能联系两次执行迭代器的删除操作。这一点
//从迭代器的注意事项可以看出
lastReturned = null;
expectedModCount++;
}
public void set(E e)
{
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}
public void add(E e)
{
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
public void forEachRemaining(Consumer<? super E> action)
{
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size)
{
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
final void checkForComodification()
{
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
LinkedList的DescendingIterator内部实现
由于ListIterator的实现类ListItr既可以正序也可以倒序排列,该方法将倒序排列的实现逻辑委托给了ListItr。内部持有一个ListItr的实例。
这样封装了部分需要的接口,向调用者隐藏了部分接口。
private class DescendingIterator implements Iterator<E>
{
private final ListItr itr = new ListItr(size());
public boolean hasNext()
{
return itr.hasPrevious();
}
public E next()
{
return itr.previous();
}
public void remove()
{
itr.remove();
}
}
迭代器的注意事项
在获取了迭代器之后,不能连续两次执行remove方法,也不能再执行set方法,因为从代码中可以看出在执行了一次remove方法之后将lastReturned置为了null。如果再次执行将抛出java.lang.IllegalStateException。
LinkedList<Integer> list = new LinkedList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Iterator<Integer> it = list.iterator();
while(it.hasNext())
{
System.out.println(it.next());
it.remove();
it.remove();
}
如何执意这么做,你将收到一个异常大礼包
LinkedList内部的序列化机制
superClone方法
@SuppressWarnings("unchecked")
private LinkedList<E> superClone()
{
try
{
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
clone方法
/**
* 返回该list的一个浅复制,就是复制该list一份。但是由于linkedList存放的元素都是引用类型的,因此内部保存的就是引用
* 的地址。所以复制内部的元素并没有复制。
*/
public Object clone()
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
writeObject方法
/**
* 保存LinkedList的状态到一个流中
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
{
// Write out any hidden serialization magic
s.defaultWriteObject();
// Write out size
s.writeInt(size);
// Write out all elements in the proper order.
for (Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item);
}
readObject方法
/**
* 从流中重建list。
*/
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException
{
// Read in any hidden serialization magic
s.defaultReadObject();
// Read in size
int size = s.readInt();
// Read in all elements in the proper order.
for (int i = 0; i < size; i++)
linkLast((E)s.readObject());
}
其他方法
/**
* 将元素e插入的节点suss的前面。succ不能为null
*/
void linkBefore(E e, Node<E> succ)
{
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
/**
* 返回一个包含该集合中链表的所有元素的数组。数组的容量=链表中元素的数量
* 注意该数组是新创建的,外部可以随意的修改,但是通过代码可知,内部的元素仍然是传递的引用的地址值。
* 所以修改数组中元素的属性会影响到list内部。
*/
public Object[] toArray()
{
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
/**
* 该方法通过传入一个泛型类型的数组,如果集合中的元素数量小于传入的数组的容量,那么
* 就将集合中的元素复制到传入的数组中,此时如果数组中还有剩余空间,那么数组中第size(集合中的元素的数量)
* 设置为null,以供调用者区分(前提是调用者确定集合中不存在非空元素)。
* 如果传入的数组不能装下集合中的所有元素,那么就新创建一个与传入数组相同类型的新数组,容量为size。
*并将集合中的元素复制到新数组中返回。
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a)
{
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
if (a.length > size)
a[size] = null;
return a;
}
java8新增API
/** A customized variant of Spliterators.IteratorSpliterator */
static final class LLSpliterator<E> implements Spliterator<E>
{
static final int BATCH_UNIT = 1 << 10; // batch array size increment
static final int MAX_BATCH = 1 << 25; // max batch array size;
final LinkedList<E> list; // null OK unless traversed
Node<E> current; // current node; null until initialized
int est; // size estimate; -1 until first needed
int expectedModCount; // initialized when est set
int batch; // batch size for splits
LLSpliterator(LinkedList<E> list, int est, int expectedModCount)
{
this.list = list;
this.est = est;
this.expectedModCount = expectedModCount;
}
final int getEst()
{
int s; // force initialization
final LinkedList<E> lst;
if ((s = est) < 0)
{
if ((lst = list) == null)
s = est = 0;
else
{
expectedModCount = lst.modCount;
current = lst.first;
s = est = lst.size;
}
}
return s;
}
public long estimateSize()
{
return (long) getEst();
}
public Spliterator<E> trySplit()
{
Node<E> p;
int s = getEst();
if (s > 1 && (p = current) != null)
{
int n = batch + BATCH_UNIT;
if (n > s)
n = s;
if (n > MAX_BATCH)
n = MAX_BATCH;
Object[] a = new Object[n];
int j = 0;
do { a[j++] = p.item; } while ((p = p.next) != null && j < n);
current = p;
batch = j;
est = s - j;
return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
}
return null;
}
public void forEachRemaining(Consumer<? super E> action)
{
Node<E> p; int n;
if (action == null) throw new NullPointerException();
if ((n = getEst()) > 0 && (p = current) != null)
{
current = null;
est = 0;
do
{
E e = p.item;
p = p.next;
action.accept(e);
} while (p != null && --n > 0);
}
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
}
public boolean tryAdvance(Consumer<? super E> action)
{
Node<E> p;
if (action == null) throw new NullPointerException();
if (getEst() > 0 && (p = current) != null)
{
--est;
E e = p.item;
current = p.next;
action.accept(e);
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
return false;
}
public int characteristics()
{
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}