Java中删除元素方法你真的懂了吗?

回顾最初接触的删除元素的方法(在线性表中的删除)

删除方法:就是将要删除的后续元素前移,然后修改数组长度(下面代码是由后面向前遍历(逆遍历)):

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)),但它真的是最安全,最快捷的删除方法吗?

咱来看看源码它是怎么个实现的吧:

Java中删除元素方法你真的懂了吗?_第1张图片

 上面那个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遍历删除呢?

答案是不可以用这个进行删除的。

首先我们得搞清楚foreach遍历元素的时候,是生成iterator,然后用它进行遍历的。

生成iterator,相对应的集合有个参数expectedModcound,这个参数会初始化为在生成iterator前修改该集合的次数,也就是会和List中的Modcound会相同(iterator接口中有检测expectModcound 和 Modcound是否相同的方法,如果不相同会抛出异常)当我们用foreach去遍历,然后用list去删除时,Modcound会随删除而改变,这时候expectModcound与Modcound不相同,那么会抛出异常。

Java中删除元素方法你真的懂了吗?_第2张图片

(当我们用foreach删除元素时候会抛出异常, 所以应避免使用它进行该操作)

用线性表删除并不是很简洁。那有没有更好的删除方式呢?

迭代器iterator遍历删除

下面是《阿里巴巴泰山开发手册》上的一个点:

Java中删除元素方法你真的懂了吗?_第3张图片

 下面是用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集合方法进行删除

Java中删除元素方法你真的懂了吗?_第4张图片

 

你可能感兴趣的:(Java,java,开发语言)