在日常开发中,我们常遇到将一个List列表分割成多个的场景,List提供了subList()方法避免开发者重复造轮子。
subList()的用法ArrayList类是接口List的一个实现,以下subList()使用方法参考示例来自ArrayList。
List arrayList = new ArrayList<>();arrayList.add("hello");arrayList.add("hello1");arrayList.add("hello2");arrayList.add("hello3");List subString = arrayList.subList(0, 1);System.out.println(subString);
输出:
[hello]
subList实现ArrayList的subList()源码如下:
public List subList(int fromIndex, int toIndex) {subListRangeCheck(fromIndex, toIndex, size);return new SubList(this, offset, fromIndex, toIndex);
}
SubList类是ArrayList的一个内部类,它继承自AbstractList抽象类,在SubList的构造方法中,入参有原始list的引用,SubList类的get方法源码如下:
//ArrayList的原始数组
transient Object[] elementData; @SuppressWarnings("unchecked")
E elementData(int index) {return (E) elementData[index];
}/*** Returns the element at the specified position in this list.** @param index index of the element to return* @return the element at the specified position in this list* @throws IndexOutOfBoundsException {@inheritDoc}*/
public E get(int index) {rangeCheck(index);return elementData(index);
}
可以看到,SubList的get()方法是通过下标来获取原数组的数据,而不是返回一个新的对象,当代码中有对分割后的列表访问时,便是对原ArrayList的引用,导致该对象不会被GC回收,数据量大时,有导致OOM的风险。因此,我们需要找到新的方案去解决代码中的风险点。
使用Stream的方式分割。
skip()方法获取某个元素节点之后的数据//获取第2个节点后的数据(包含第2个元素)
List skipList = arrayList.stream().skip(1).collect(Collectors.toList());
输出:
[hello2, hello3]
//获取第2个节点前的数据
List limitList = arrayList.stream().limit(1).collect(Collectors.toList());
输出:
[hello]
Lists.partition()ListUtils.partition()详细方案请参考:
https://juejin.cn/post/7029519771670413325