在Java中,subList是List接口的一个方法,用于获取原始列表的子列表
方法的声明如下
List<E> subList(int fromIndex, int toIndex);
fromIndex
:起始索引(包括)toIndex
:结束索引(不包括)List<Object> list = new Arraylist<>();
List<Object> subList = list.subList(0, 5);
返回的子列表是原始列表的一个视图,对子列表的修改会反映在原始列表上,反之亦然。
例如,下面的语句从列表中移除了元素的范围:
list.subList(from, to).clear();
下面是一个简单的例子:
List<String> originalList = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
List<String> subList = originalList.subList(1, 4);
System.out.println("subList = " + subList); // 子列表包括索引 1,2,3 输出:[B, C, D]
System.out.println("originalList = " + originalList); // 输出:[A, B, C, D, E]
subList.add("F");
System.out.println("subList = " + subList); // 输出: [B, C, D, F]
System.out.println("originalList = " + originalList);// 输出:[A, B, C, D, F, E] 因为通过subList视图对索引为4的位置添加了一个F
originalList.add("G");
// 调用subList()后,如果再对原list进行操作同时对subList()也进行操作(打印、添加、清除),都会报错ConcurrentModificationException,因为这会修改视图的结构
// subList.add("H") java.util.ConcurrentModificationException
// System.out.println(subList); java.util.ConcurrentModificationException
System.out.println("originalList = " + originalList); // 输出:[A, B, C, D, F, E, G]
originalList.subList(1, 2).clear();
System.out.println("originalList = " + originalList); // 输出: [A, C, D, F, E, G] 因为通过视图对索引为1的数据进行了清除
说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList ,而是 ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上。
fromIndex
至 toIndex
是左闭右开的范围,即包括 fromIndex
处的元素,但不包括 toIndex
处的元素。ConcurrentModificationException
异常。结构性修改是指改变原列表的大小或者使其元素的数量发生变化的操作。 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>{}
?LinkedList并没有覆盖这个方法.ArryList自己覆盖了这个方法,返回的是java.util.ArrayList.SubList
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
声明:
private class SubList extends AbstractList<E> implements RandomAccess {}
看来ArryList处处体现出RandomAccess接口的特性——支持随机访问。
public void clear() {
removeRange(0, size());
}
...
// ArrayList的覆盖
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
...
// LinkedList的覆盖
public void clear() {
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++;
}
...
// 根据上面,截短一个List的正确姿势
list.subList(from, to).clear();
大家可以看一下我的慢查询优化实战文章
在最开始分页慢查询优化没有得到较好的解决方案时,我的操作是直接获取到全部数据的List,然后对List进行截取,达到分页的效果,这是相关的代码
public static <T> IPage<T> listToPage(List<T> list, Integer current, Integer size){
IPage<T> iPage = new Page<>(current,size);
iPage.setTotal(list.size());
int startIndex = (int)((current - 1)*size);
if(null == list || list.isEmpty() || startIndex > list.size()){
iPage.setRecords(new ArrayList<>());
}
else {
int toIndex = (int)(current*size);
iPage.setRecords(list.subList(startIndex,toIndex > list.size() ? list.size() : toIndex));
}
return iPage;
}
大家可以看到,我对List是只截取不操作的,也就不会出现bug
注意!subList是返回一个镜像而不是新示例,用了得保证原来的list不能更改!
over
参考