回顾最初接触的删除元素的方法(在线性表中的删除)
删除方法:就是将要删除的后续元素前移,然后修改数组长度(下面代码是由后面向前遍历(逆遍历)):
package ly.csdn.text; public class Sort1 { private static int size;//原始数组长度 public static void main(String[] args) { //定义一个数组(线性表) int[] arr = {4513,323,2342,24,62,314,53,324}; size = arr.length;//初始化原始数组长度 //删除小于俩百的元素 for(int i=size-1;i>=0;--i) { if(arr[i]<200) { delete(arr,i); --size; } } //输出删除后的序列 for(int i=0;i
(这是删除后序列元素)
如果是由前面开始遍历呢?会有预期的结果吗?(以下是错误结果示范)
package ly.csdn.text; public class Sort1 { private static int size;//原始数组长度 public static void main(String[] args) { //定义一个数组(线性表) int[] arr = {4513,323,2342,24,62,314,53,324}; size = arr.length;//原始数组长度初始化 //删除小于俩百的元素 for(int i=0;i
查看输出结果,我们发现62没有被删除成功,这是为什么呢?
这是因为删除24后,62被移动到了24这个位置,而 i 仍然在移动所以,错过了访问62的机会,导致没有删除成功。
当然学了集合后,我们清楚可以直接调用方法库直接对元素进行删除(remove(int index)/remove(Object o)),但它真的是最安全,最快捷的删除方法吗?
咱来看看源码它是怎么个实现的吧:
上面那个remove咱不看(只是为了连贯就一起截过来了)咱看看 fastRemove方法。
分析代码:
newsize是定义删除元素后的新长度的(newSize = size - 1和上面线性表所写的 --size 差不多一个含义)
当newSize == i呢就说明删除的元素是最后一个元素,直接退出了判断语句
es[size = newSize] = null 也就是把原先最后一个元素置为空,也就是除去了
它中间调用了System类中的一个方法arraycopy(Object src,int srcPos,Object dest,int destPos,int length)咱看这个方法参数名字也能猜中大概吧:就是把src对象数组索引从dest开始长为length的序列复制到dest索引从destPos的数组中。
这里System.arraycopy(es,i+1,es,i,newSize-i)就是es从i+1开始长为newSize-i(和size-i+1等价,就是索引i后面那段序列)从索引 i 开始复制到es数组(自己本身,自己复制给自己)中去。
对源码分析后发现了啥没?
这不就是和线性表删除结果是一样的,只是它调用了方法库,使用方便了,既然是一样,那么使用它删除多个元素时候就要注意了不可以向前遍历(删除一个的话无所谓,啥方法都一样)。
当我们顺序遍历删除的时候得注意点了,防止出错:
package ly.csdn.text;
import java.util. *;
public class Sort1 {
public static void main(String[] args) {
//定义一个数组(线性表)
List list = new ArrayList<>();
//存入元素
list.add(203);
list.add(218);
list.add(139);
list.add(352);
//删除小于俩百的元素
for(int i=0;i
(逆遍历删除是可以的不会出错)
答案是不可以用这个进行删除的。
首先我们得搞清楚foreach遍历元素的时候,是生成iterator,然后用它进行遍历的。
生成iterator,相对应的集合有个参数expectedModcound,这个参数会初始化为在生成iterator前修改该集合的次数,也就是会和List中的Modcound会相同(iterator接口中有检测expectModcound 和 Modcound是否相同的方法,如果不相同会抛出异常)当我们用foreach去遍历,然后用list去删除时,Modcound会随删除而改变,这时候expectModcound与Modcound不相同,那么会抛出异常。
(当我们用foreach删除元素时候会抛出异常, 所以应避免使用它进行该操作)
用线性表删除并不是很简洁。那有没有更好的删除方式呢?
下面是《阿里巴巴泰山开发手册》上的一个点:
下面是用iterator进行删除的代码:
package ly.csdn.text;
import java.util. *;
public class Sort1 {
public static void main(String[] args) {
//定义一个数组(线性表)
List list = new ArrayList<>();
//存入元素
list.add(203);
list.add(218);
list.add(139);
list.add(120);
list.add(352);
//删除小于俩百的元素
Iterator it = list.iterator();
while(it.hasNext()) {
Integer x = it.next();
if(x<200)
it.remove();
}
//输出删除后的序列【203,218,352】
for(int i=0;i
用iterator进行删除也要注意:不能同时进行俩次及俩次以上的删除(remove()),这和成员变量cursor(当前遍历的位置)和lastRet(上一次遍历的位置)有关,操作时是对cursor进行操作,操作完cursor会被设值为-1,如果还对它进行操作,那就会抛出数组越界异常,详细看这篇文档有对其的解释(源码分析):Java List用迭代器删除源码细节
除了上述所写的,我们还可以用List接口中提供的removeAll(Collection> c)方法。
我们可以创建一个集合对象,里面存放要删除的元素,然后再用removeAll方法进行删除即可。
如代码所示:
package ly.csdn.text;
import java.util. *;
public class Sort1 {
public static void main(String[] args) {
//定义一个数组(线性表)
List list = new ArrayList<>();
//存入元素
list.add(203);
list.add(218);
list.add(139);
list.add(120);
list.add(352);
//删除小于俩百的元素
List listDelete = new ArrayList<>();
for(Integer x:list) {
if(x<200)
listDelete.add(x);
}
list.removeAll(listDelete);
//输出删除后的序列【203,218,352】
for(int i=0;i
1. 叙述了用线性表删除式删除应该注意的点,如果要用记得 --i 或者采用逆遍历的思想;
2. 叙述了为什么不能foreach遍历来删除元素
3. 强烈建议用 iterator 迭代器的方式进行删除元素或遍历元素
4. 用迭代器删除时不能一次性多次进行删除,原因和源码中成员变量cursor和lastRet有关
5. 拓展了用removeAll集合方法进行删除