Android避坑系列之List的subList谨慎使用

一、场景

我们知道String类有分割字符串的作用(subString函数),当然在List集合里面也提供了分割集合的作用(subList函数)。

但List的这个分割方法有坑啊,如下面代码:

1、正常使用:

ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
List<String> list = arrayList.subList(0, 2);
System.out.println(list);

输出:

 2、带坑的使用:

List<String> arrayList = new ArrayList<String>();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
List<String> arrayList_subList = arrayList.subList(0, 2);
arrayList.remove(0);
arrayList.add("d");
System.out.println(arrayList_subList.size());

输出:

 最后一行报错。按正常的代码逻辑思维,arrayList_subList新建了一个新对象List,保存分割的数据,后续父List的改变应该不影响子List的,但是不是的。

二、原因分析:

看这个函数的官方文档:

/**
 * Returns a view of the portion of this list between the specified
 * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
 * {@code fromIndex} and {@code toIndex} are equal, the returned list is
 * empty.)  The returned list is backed by this list, so non-structural
 * changes in the returned list are reflected in this list, and vice-versa.
 * The returned list supports all of the optional list operations supported
 * by this list.<p>
 *
 * This method eliminates the need for explicit range operations (of
 * the sort that commonly exist for arrays).  Any operation that expects
 * a list can be used as a range operation by passing a subList view
 * instead of a whole list.  For example, the following idiom
 * removes a range of elements from a list:
 * <pre>{@code
 *      list.subList(from, to).clear();
 * }</pre>
 * Similar idioms may be constructed for {@code indexOf} and
 * {@code lastIndexOf}, and all of the algorithms in the
 * {@code Collections} class can be applied to a subList.<p>
 *
 * The semantics of the list returned by this method become undefined if
 * the backing list (i.e., this list) is <i>structurally modified</i> in
 * any way other than via the returned list.  (Structural modifications are
 * those that change the size of this list, or otherwise perturb it in such
 * a fashion that iterations in progress may yield incorrect results.)
 *
 * @param fromIndex low endpoint (inclusive) of the subList
 * @param toIndex high endpoint (exclusive) of the subList
 * @return a view of the specified range within this list
 * @throws IndexOutOfBoundsException for an illegal endpoint index value
 *         ({@code fromIndex < 0 || toIndex > size ||
 *         fromIndex > toIndex})
 */

 根据注释得知:

1,该方法返回的是父list的一个视图,从fromIndex(包含),到toIndex(不包含)。fromIndex=toIndex 表示子list为空

2,父子list做的非结构性修改(non-structural changes)都会影响到彼此:所谓的“非结构性修改”,是指不涉及到list的大小改变的修改。相反,结构性修改,指改变了list大小的修改。

3,对于结构性修改,子list的所有操作都会反映到父list上。但父list的修改将会导致返回的子list失效

4,tips:如何删除list中的某段数据:

list.subList(from, to).clear();

下面一段代码验证第三点:

List<String> list = new ArrayList<String>();  
list.add("a");  
  
// 使用构造器创建一个包含list的列表list1  
List<String> list1 = new ArrayList<String>(list);  
// 使用subList生成与list相同的列表list2  
List<String> list2 = list.subList(0, list.size());  
list2.add("b");  
  
System.out.println(list.equals(list1));  
System.out.println(list.equals(list2));

输出:

 三、总结

         多看源码。

猜你喜欢

转载自blog.csdn.net/sunbinkang/article/details/121100556