在工作中的许多场景下,我们都会使用到List这个数据结构,那么同样的有很多场景下需要删除List中的某一个元素或某几个元素,那么我们该如何正确无误地删除List中的元素
知识准备 for循环的执行顺序 这里借用百度百科的一张图,简明扼要的介绍一下。
Iterator迭代器介绍 迭代器:迭代其实我们可以简单地理解为遍历,是一个标准化 遍历各类容器里面的所有对象的方法类,它是一个很典型的设计模式。Iterator 模式是用于遍历集合类的标准访问方法 。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向每次遍历前都需要知道要遍历集合的内部结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 List list = new ArrayList ();list.add(1 ); list.add(2 ); for (int i = 0 ; i < list.size(); i++) { Object object = list.get(i); } Map<String,String> map = new HashMap <>(); map.put("1" ,"first" ); map.put("2" ,"second" ); for (Map.Entry<String,String> entry : map.entrySet()){ String key = entry.getKey(); String value = entry.getValue(); }
对于这两种方式,我们总是都事先知道集合的内部结构,访问代码和集合本身是紧密耦合的,无法将访问逻辑从集合类和遍历方法中分离出来。同时每一种集合对应一种遍历方法,代码无法复用。 为了解决以上问题, Iterator 模式腾空出世,它总是用同一种逻辑来遍历集合。使得需要遍历集合的人,在遍历的时候不需要了解集合的内部结构,所有的内部状态都由 Iterator 来维护。遍历集合的方法不直接和集合类打交道,它总是控制 Iterator,向它发送”向前”,”向后”,”取当前元素”的命令,就可以间接遍历整个集合。
错误:for循环顺序遍历 直接使用简单for循环,以for (int i = 0; i < list.size(); i++)
进行遍历,这种方式可能会在遍历的过程中漏掉 部分元素,从而出现少删的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static List forRemove (List list, Object element) { for (int i = 0 ; i < list.size(); i++) { if (element.equals(list.get(i))) { list.remove(i); } } return list; }
使用增强for循环是,如果删除后继续向下循环则会报java.util.ConcurrentModificationException
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static List forceForRemove (List list, Object element) { for (Object item : list) { if (item.equals(element)) { list.remove(item); } } return list; }
异常如下:
1 2 3 4 5 Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr .checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr .next(ArrayList.java:851) at com.lingyejun.leetcode.RemoveListElement.forceForRemove(RemoveListElement.java:57) at com.lingyejun.leetcode.RemoveListElement.main(RemoveListElement.java:112)
我们使用逆向遍历的方式可以得到正确的结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static List reverseorRemove (List list, Object element) { for (int i = list.size() - 1 ; i >= 0 ; i--) { if (element.equals(list.get(i))) { list.remove(i); } } return list; }
使用增强for循环,删除元素后,立即跳出,则正常退出,但缺点是不能向后继续循环了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static List forceForRemove1 (List list, Object element) { for (Object item : list) { if (item.equals(element)) { list.remove(item); break ; } } return list; }
优雅删除:使用Iterator迭代器 使用迭代器可,正确无误的删除,代码简洁优雅,推荐使用!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static List iteratorRemove (List list, Object element) { Iterator iterator = list.iterator(); while (iterator.hasNext()) { Object cur = iterator.next(); if (cur.equals(element)) { iterator.remove(); } } return list; }
优雅删除:使用Steam流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.stream.Collectors;public class Main { public static void main (String[] args) { List<Map<String, Object>> mapList = new ArrayList <>(); Map<String, Object> map1 = new HashMap <>(); map1.put("id" , 1 ); map1.put("name" , "Alice" ); mapList.add(map1); Map<String, Object> map2 = new HashMap <>(); map2.put("id" , 2 ); map2.put("name" , "Bob" ); mapList.add(map2); Map<String, Object> map3 = new HashMap <>(); map3.put("id" , 3 ); map3.put("name" , "Charlie" ); mapList.add(map3); int idToRemove = 2 ; List<Map<String, Object>> updatedMapList = mapList.stream() .filter(map -> !map.get("id" ).equals(idToRemove)) .collect(Collectors.toList()); System.out.println(updatedMapList); } }
在这个示例中,我们有一个 mapList
,其中包含了多个 Map 元素。我们希望从中删除 id
为 2 的 Map 元素。我们使用 Stream 的 filter
操作来创建一个新的流,其中不包含要删除的元素。最后,通过 collect
操作将过滤后的 Map 元素收集到一个新的 List 中。
同样地,这种方法不会改变原始的 mapList
,而是创建了一个新的 List 包含了需要保留的 Map 元素。如果需要更新原始 List,只需将 updatedMapList
赋值给 mapList
即可。
参考文章:
https://jingyan.baidu.com/article/7f766dafaa6ee04101e1d0e6.html
http://wiki.jikexueyuan.com/project/java-enhancement/java-thirty.html