Collection之List---subList

本文介绍了Java中List的subList方法,强调subList返回的是原列表的部分视图,其操作会影响原列表。通过示例展示了操作原列表导致的ConcurrentModificationException异常,并指出在使用subList后不应直接操作原列表,以保持子列表稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java中一些处理分隔的方法,例如subString—String;subList—List;subMap—Map;subSet—Set;
这里学习并整理了一下关于subList的使用
一、subList仅返回一个list的部分视图
List subList(int fromIndex, int toIndex);
实例:

public static void main(String[] args) {
	 List<String> list1 = new ArrayList<>();
	 list1.add("aaa");
	 list1.add("bbb");
	 list1.add("ccc");
	 //通过构造函数新建一个包含list1的列表 list2
	 List<String> list2 = new ArrayList<>(list1);
	 //通过subList生成一个与list1一样的列表 list3
	 List<String> list3 = list1.subList(0, list1.size());
	 System.out.println("list1 == list3:" + list1.equals(list3));
	 //修改list3
	 list3.add("ddd");
	 System.out.println("list1 == list2:" + list1.equals(list2));
	 System.out.println("修改list3后 list1 == list3:" + list1.equals(list3));
	 System.out.println("---------------list1---------------");
	 list1.forEach(n -> System.out.println(n));
	 System.out.println("---------------list2---------------");
	 list2.forEach(n -> System.out.println(n));
	 System.out.println("---------------list3---------------");
	 list3.forEach(n -> System.out.println(n));
}

实例中list1是原list;list2是通过构造函数生成一个与list1一样的list;list3是通过subList分隔出与list1一样的list。
执行结果分析:
list3未增加新元素时list1 == list3执行结果为true
list3增加新元素后list1 == list3执行结果仍为true
由此可以判断出subList方法如get、set、add、remove等都是在原列表上面做操作,subList返回的只是原列表的一个视图,它所有的操作最终都会作用在原列表上。它并没有像subString一样生成一个新的对象。

subList源码

public List<E> subList(int fromIndex, int toIndex) {
 	subListRangeCheck(fromIndex, toIndex, size);
 	return new SubList(this, 0, fromIndex, toIndex);
}

SubList方法源码片段

private class SubList extends AbstractList<E> implements RandomAccess {
	private final AbstractList<E> parent;
	private final int parentOffset;
	private final int offset;
	int size;

	SubList(AbstractList<E> parent, int offset, int fromIndex, int toIndex) {
		this.parent = parent;
		this.parentOffset = fromIndex;
		this.offset = offset + fromIndex;
		this.size = toIndex - fromIndex;
		this.modCount = ArrayList.this.modCount;
	}
	...
}

需要注意:
this.parent = parent;而parent就是在前面传递过来的list,也就是说this.parent就是原始list的引用。
this.modCount = ArrayList.this.modCount;
再看SubLsit内部类中其它的get、set、add、remove等list常用的方法

public E get(int index) {
 	rangeCheck(index);
 	checkForComodification();
 	return ArrayList.this.elementData(offset + index);
}

返回的是原列表offset + index位置的元素

二、subList生成子列表后,不要去操作原列表

public static void main(String[] args) {
	 List<String> list1 = new ArrayList<>();
	 list1.add("aaa");
	 list1.add("bbb");
	 List<String> list2 = list1.subList(0, list1.size());
	 System.out.println("---------------list1---------------");
	 list1.forEach(n -> System.out.println(n));
	 list1.add("ccc");
	 System.out.println("---------------list2---------------");
	 list2.forEach(n -> System.out.println(n));
}

执行结果分析:

---------------list1---------------
aaa
bbb
---------------list2---------------
Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1239)
 at java.util.ArrayList$SubList.listIterator(ArrayList.java:1099)
 at java.util.AbstractList.listIterator(AbstractList.java:299)
 at java.util.ArrayList$SubList.iterator(ArrayList.java:1095)
 at java.lang.Iterable.forEach(Iterable.java:74)

遍历list1正常、遍历list2就抛出ConcurrentModificationException异常、从异常日志中可以看到会执行checkForComodification方法

private void checkForComodification() {
 	if (ArrayList.this.modCount != this.modCount)
 	 throw new ConcurrentModificationException();
}

该方法表明当原列表的modCount与this.modCount不相等时就会抛出ConcurrentModificationException。同时我们在subList过程中modCount“继承”了原列表modCount,只有在修改子列表时才会修改该值(先表现在原列表后作用于子列表)。而该实例我们是操作原列表,原列表的modCount不会反应在子列表的modCount上,操作原列表子列表将会失效,变得不可用,所以才会抛出该异常,所以subList生成子列表后,不要去操作原列表,否则会造成子列表的不稳定而产生异常。
(关于ConcurrentModificationException异常,可以详细了解下fail-fast机制)

三、通过subList处理局部列表

如果想删除一个list的某个区段,比如删除list的第30-50个元素?
实例:

list1.subList(30, 50).clear();//list.subList(from, to).clear();因为子列表的操作都会反映在原列表上

文章仅作为个人学习整理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值