参考书籍:《编写高质量代码:改善Java程序的151个建议》
- Arraylist & LinkedList
增删改查效率:
Arraylist
底层数据结构是数组,存在索引,所以改查效率高于LinkedList
。而LinkedList
底层数据结构是双向链表,所以增删效率高于Arraylist
。
PS:所谓增删效率高于数组结构,意思是随机位置增删,而不是顺序增删。所以for循环顺序添加元素时,LinkedList
的效率并不高于Arraylist
。
遍历效率:
首先看JDK文档RandomAccess
接口的描述中有以下一段话:
this loop:
for (int i=0, n=list.size(); i < n; i++)
list.get(i);
runs faster than this loop:
for (Iterator i=list.iterator(); i.hasNext(); )
i.next();
也就是说实现了RandomAccess
接口的类遍历时,用索引方式遍历效率高于迭代器方式遍历
,而增强for
循环的原理就是利用迭代器来遍历元素。
所以,Arraylist
遍历时,尽量使用索引方式遍历。
- Arraylist & HashMap
初始化:
Arraylist
底层结构是数组,HashMap
的底层结构是数组+链表(JDK8中的结构是数组+链表+红黑树),所以创建对象时,尽量设置初始化容量,避免容器无谓的扩容带来的性能损失。
Arraylist
:初始化容量 = 元素个数,默认值10
HashMap
:初始化容量 = 元素个数 / 加载因子(加载因子默认值:0.75),相除的结果向上取整且为2的N次方,默认值16
扩容倍数:
Arraylist
:当元素个数超过容器 size 时,容器扩容后size = 扩容前size * 1.5
HashMap
:当元素个数超过容器 size * 0.75 时,容器扩容后size = 扩容前size * 2
- List中的subList()方法
先看JDK源码:
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
class SubList<E> extends AbstractList<E> {
private final AbstractList<E> l;
private final int offset;
private int size;
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
l = list;
offset = fromIndex;
size = toIndex - fromIndex;
this.modCount = l.modCount;
}
public E set(int index, E element) {
rangeCheck(index);
checkForComodification();
return l.set(index+offset, element);
}
public E get(int index) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
}
...
}
调用list.subList()
方法返回的新的List集合,其内部引用的还是原来的list,所以两个list的内部元素都是同一个元素。即:对返回的list集合操作就是对原来的集合操作,此时操作需要谨慎。
一般来说,使用list.subList()
方法后,不会再对原来的list进行操作了。