sublist用法Java
sublist用法Java
咱们常用subString方法来对String对象进行分割处理,同时咱们也可使用subList、subMap、subSet来对List、Map、Set进行分割处理,可是这个分割存在某些瑕疵。java
1、subList返回仅仅只是一个视图
首先咱们先看以下实例:dom
public static void main(String[] args) {
List list1 = new ArrayList();
list1.add(1);
list1.add(2);
//经过构造函数新建一个包含list1的列表 list2
List list2 = new ArrayList(list1);
//经过subList生成一个与list1同样的列表 list
List list = list1.subList(0, list1.size());
//修改list
list.add();
println(list1 == list2: (list2));
println(list1 == list: (list));
}
这个例子很是简单,无非就是经过构造函数、subList从新生成一个与list1同样的list,而后修改list,最后比较list1 == list2?、list1 == list?。按照咱们常规的思路应该是这样的:由于list经过add新增了一个元素,那么它确定与list1不等,而list2是经过list1构造出来的,因此应该相等,因此结果应该是(错):函数
list1 == list2:true
list1 == list: false
首先咱们先不论结果的正确与否,咱们先看subList的源码:this
public List subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
subListRangeCheck方式是判断fromIndex、toIndex是否合法,若是合法就直接返回一个subList对象,注意在产生该new该对象的时候传递了一个参数 this ,该参数很是重要,由于他表明着原始list。spa
/**
* 继承AbstractList类,实现RandomAccess接口
*/
private class SubList extends AbstractList implements RandomAccess {
private final AbstractList parent; //列表
private final int parentOffset;
private final int offset;
int size;
//构造函数
SubList(AbstractList parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
= offset fromIndex;
this.size = toIndex - fromIndex;
= ArrayList.;
}
//set方法
public E set(int index, E e) {
rangeCheck(index);
checkForComodification();
E oldValue = (offset index);
[offset index] = e;
return oldValue;
}
//get方法
public E get(int index) {
rangeCheck(index);
checkForComodification();
return (offset index);
}
//add方法
public void add(int index, E e) {
rangeCheckForAdd(index);
checkForComodification();
parent.add(parentOffset index, e);
= ;
this.size;
}
//remove方法
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = parent.remove(parentOffset index);
= ;
this.size--;
return result;
}
}
该SubLsit是ArrayList的内部类,它与ArrayList同样,都是继承AbstractList和实现RandomAccess接口。同时也提供了get、set、add、remove等list经常使用的方法。可是它的构造函数有点特殊,在该构造函数中有两个地方须要注意:code
一、this.parent = parent;而parent就是在前面传递过来的list,也就是说this.parent就是原始list的引用。对象
二、 = offset fromIndex;this.parentOffset = fromIndex;。同时在构造函数中它甚至将modCount(fail-fast机制)传递过来了。blog
咱们再看get方法,在get方法中return (offset index);这段代码能够清晰代表get所返回就是原列表offset index位置的元素。一样的道理还有add方法里面的:继承
parent.add(parentOffset index, e);
= ;
remove方法里面的接口
E result = parent.remove(parentOffset index);
= ;
诚然,到了这里咱们能够判断subList返回的SubList一样也是AbstractList的子类,同时它的方法如get、set、add、remove等都是在原列表上面作操做,它并无像subString同样生成一个新的对象。因此subList返回的只是原列表的一个视图,它全部的操做最终都会做用在原列表上。
那么从这里的分析咱们能够得出上面的结果应该偏偏与咱们上面的答案相反:
list1 == list2:false
list1 == list:true
Java细节(.1):subList返回的只是原列表的一个视图,它全部的操做最终都会做用在原列表上
2、subList生成子列表后,不要试图去操做原列表
从上面咱们知道subList生成的子列表只是原列表的一个视图而已,若是咱们操做子列表它产生的做用都会在原列表上面表现,可是若是咱们操做原列表会产生什么状况呢?
public static void main(String[] args) {
List list1 = new ArrayList();
list1.add(1);
list1.add(2);
//经过subList生成一个与list1同样的列表 list
List list = list1.subList(0, list1.size());
//修改list
list1.add();
println(list1 size: list1.size());
println(list size: list.size());
}
该实例若是不产生意外,那么他们两个list的大小都应该都是,可是恰恰事与愿违,事实上咱们获得的结果是这样的:
list1 size:
Exception in thread main java.util.ConcurrentModificationException
at java.util.ArrayList$(Unknown Source)
at java.util.ArrayList$SubList.size(Unknown Source)
at arrayList.(SubListTest.java:17)
list1正常输出,可是list就抛出ConcurrentModificationException异常,看过我另外一篇博客的同仁确定对这个异常很是,fail-fast?不错就是fail-fast机制,在fail-fast机制中,LZ花了不少力气来说述这个异常,因此这里LZ就不对这个异常多讲了(更多请点这里:Java提升篇(三四)—–fail-fast机制)。咱们再看size方法:
public int size() {
checkForComodification();
return this.size;
}
size方法首先会经过checkForComodification验证,而后再返回this.size。
private void checkForComodification() {
if (ArrayList. != )
throw new ConcurrentModificationException();
}
该方法代表当原列表的modCount与不相等时就会抛出ConcurrentModificationException。同时咱们知道modCount 在new的过程当中 “继承”了原列表modCount,只有在修改该列表(子列表)时才会修改该值(先表如今原列表后做用于子列表)。而在该实例中咱们是操做原列表,原列表的modCount固然不会反应在子列表的modCount上啦,因此才会抛出该异常。
对于子列表视图,它是动态生成的,生成以后就不要操做原列表了,不然必然都致使视图的不稳定而抛出异常。最好的办法就是将原列表设置为只读状态,要操做就操做子列表:
//经过subList生成一个与list1同样的列表 list
List list = list1.subList(0, list1.size());
//对list1设置为只读状态
list1 = Collecti.unmodifiableList(list1);
Java细节(.2):生成子列表后,不要试图去操做原列表,不然会形成子列表的不稳定而产生异常
、推荐使用subList处理局部列表
在开发过程当中咱们必定会遇到这样一个问题:获取一堆数据后,须要删除某段数据。例如,有一个列表存在1000条记录,咱们须要删除100-200位置处的数据,可能咱们会这样处理:
for(int i = 0 ; i
if(i >= 100 && i <= 200){
list1.remove(i);
/*
* 固然这段代码存在问题,list remove以后后面的元素会填充上来,
* 因此须要对i进行简单的处理,固然这个不是这里讨论的问题。
*/
}
}
这个应该是咱们大部分人的处理方式吧,其实还有更好的方法,利用subList。在前面LZ已经讲过,子列表的操做都会反映在原列表上。因此下面一行代码所有搞定:
list1.subList(100, 200).clear();
简单而不失华丽!!!!!
参考资料:编写高质量代码:改善Java程序的151个建议
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
推荐阅读
留言与评论(共有 14 条评论) |
本站网友 药品推广 | 18分钟前 发表 |
同时咱们知道modCount 在new的过程当中 “继承”了原列表modCount,只有在修改该列表(子列表)时才会修改该值(先表如今原列表后做用于子列表) | |
本站网友 315现货白银 | 7分钟前 发表 |
最好的办法就是将原列表设置为只读状态,要操做就操做子列表://经过subList生成一个与list1同样的列表 listList list = list1.subList(0 | |
本站网友 牛蛙的营养价值 | 25分钟前 发表 |
int toIndex) {this.parent = parent;this.parentOffset = fromIndex; = offset fromIndex;this.size = toIndex - fromIndex; = ArrayList.;}//set方法public E set(int index | |
本站网友 28天后 | 21分钟前 发表 |
toIndex | |
本站网友 苏格拉底故事 | 27分钟前 发表 |
int toIndex) {subListRangeCheck(fromIndex | |
本站网友 ie7浏览器 | 29分钟前 发表 |
remove等list经常使用的方法 | |
本站网友 衡阳皮肤科医院 | 27分钟前 发表 |
Map | |
本站网友 linux视频教程 | 17分钟前 发表 |
可是它的构造函数有点特殊,在该构造函数中有两个地方须要注意:code一 | |
本站网友 黄石声屏网 | 21分钟前 发表 |
add | |
本站网友 稳盈 | 1分钟前 发表 |
toIndex);}subListRangeCheck方式是判断fromIndex | |
本站网友 尚德机构怎么样 | 19分钟前 发表 |
subList从新生成一个与list1同样的list,而后修改list,最后比较list1 == list2? | |
本站网友 合肥房屋出租 | 12分钟前 发表 |
int fromIndex | |
本站网友 鬼谷 | 23分钟前 发表 |
remove等都是在原列表上面作操做,它并无像subString同样生成一个新的对象 |