关于List比较好玩的操作

本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/9347357

作为Java大家庭中的集合类框架,List应该是平时开发中最常用的,可能有这种需求,当集合中的某些元素符合一定条件时,想要删除这个元素。如:

[java] view plain copy

print?

  1. public class ListTest {
  2. public static void main(String[] args) {
  3. List<Integer> intList = new ArrayList<Integer>();
  4. Collections.addAll(intList, 1, 2, 3, 5, 6);
  5. // for循环优化写法,只获取一次长度
  6. for(int i = 0, size = intList.size(); i < size; i++) {
  7. Integer value = intList.get(i);
  8. // 符合条件,删除元素
  9. if(value == 3 || value == 5) {
  10. intList.remove(i);
  11. }
  12. }
  13. System.out.println(intList);
  14. }
  15. }

执行后,会抛出IndexOutOfBoundsException,因为集合中存在符合条件的元素,删除后,集合长度动态改变,由于长度只获取一次,发生越界,所以,去掉for循环优化,如:

[java] view plain copy

print?

  1. public class ListTest {
  2. public static void main(String[] args) {
  3. List<Integer> intList = new ArrayList<Integer>();
  4. Collections.addAll(intList, 1, 2, 3, 5, 6);
  5. for(int i = 0; i < intList.size(); i++) {
  6. Integer value = intList.get(i);
  7. // 符合条件,删除元素
  8. if(value == 3 || value == 5) {
  9. intList.remove(i);
  10. }
  11. }
  12. System.out.println(intList);
  13. }
  14. }

输出:[1, 2, 5, 6],漏掉了5这个元素,当i=2的时候,值为3,删除后,后面的元素往前补一位,这时i=3的时候,值为6,跳过了5,这样也不行,随后想到了用for循环增强,不显示的操作下标,直接操作对象,如:

[java] view plain copy

print?

  1. public class ListTest {
  2. public static void main(String[] args) {
  3. List<Integer> intList = new ArrayList<Integer>();
  4. Collections.addAll(intList, 1, 2, 3, 5, 6);
  5. for(Integer value : intList) {
  6. // 符合条件,删除元素
  7. if(value == 3 || value == 5) {
  8. intList.remove(value);
  9. }
  10. }
  11. System.out.println(intList);
  12. }
  13. }

执行后,会抛出ConcurrentModificationException,字面意思是并发修改异常。异常跟踪信息如下:

Exception inthread "main" java.util.ConcurrentModificationException

atjava.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)

at java.util.AbstractList$Itr.next(AbstractList.java:420)

at ListTest.main(ListTest.java:13)

可以大概看出是执行到AbstractList中内部类Itr的checkForComodification方法抛出的异常,至于为什么出现异常,这里可以大概解释一下。集合遍历是使用Iterator, Iterator是工作在一个独立的线程中,并且拥有一个互斥锁。Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast原则 Iterator 会马上抛出java.util.ConcurrentModificationException 异常。所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。

而要解决这个问题,可以使用Iterator的remove方法,该方法会删除当前迭代对象的同时,维护索引的一致性。如:

[java] view plain copy

print?

  1. public class ListTest {
  2. public static void main(String[] args) {
  3. List<Integer> intList = new ArrayList<Integer>();
  4. Collections.addAll(intList, 1, 2, 3, 5, 6);
  5. Iterator<Integer> it = intList.iterator();
  6. while(it.hasNext()) {
  7. Integer value = it.next();
  8. if(value == 3 || value == 5) {
  9. it.remove();
  10. }
  11. }
  12. System.out.println(intList);
  13. }
  14. }

输出正确结果:[1, 2, 6]。

不使用迭代器的解决方案就是,自己维护索引,删除一个元素后,索引-1,如:

[java] view plain copy

print?

  1. public class ListTest {
  2. public static void main(String[] args) {
  3. List<Integer> intList = new ArrayList<Integer>();
  4. Collections.addAll(intList, 1, 2, 3, 5, 6);
  5. for(int i = 0; i < intList.size(); i++) {
  6. Integer value = intList.get(i);
  7. if(value == 3 || value == 5) {
  8. intList.remove(i);
  9. i--;
  10. }
  11. }
  12. System.out.println(intList);
  13. }
  14. }

输出正确结果:[1, 2, 6]。

还有种取巧的方式是从最后一个元素开始遍历,符合条件的删除,如:

[java] view plain copy

print?

  1. public class ListTest {
  2. public static void main(String[] args) {
  3. List<Integer> intList = new ArrayList<Integer>();
  4. Collections.addAll(intList, 1, 2, 3, 5, 6);
  5. for(int i = intList.size() - 1; i >= 0; i--) {
  6. Integer value = intList.get(i);
  7. if(value == 3 || value == 5) {
  8. intList.remove(i);
  9. }
  10. }
  11. System.out.println(intList);
  12. }
  13. }

输出正确结果:[1, 2, 6]。

最后,Java集合类框架真是大大方便了开发,不用自己去维护数组,随时担心着越界等问题。当然List的实现类对插入、删除的效率不太一样,这取决于其实现的数据结构,是选择删除,还是选择新建个集合,这里就不做讨论了。

时间: 2024-11-05 04:38:32

关于List比较好玩的操作的相关文章

Python的一个“骚操作”!

PS作为世界四大发明之一可以说被广大网友用到了极致,只有你想不到的没有我P不了的,任何正经的图片在都可以变成搞笑图片(比如下图)当然也可以用ps做一点正经的事情. 作为一个爱折腾的程序猿能用代码的解决的事情绝对不会用其他的方式,Python可以打飞机,人工降雪,那么p个图对于Python来说是小儿科了,今天就教给大家Python之p图大法. 具体介绍 今天P图主要用到的就是PIL库. PIL(Python Image Library)是python的第三方图像处理库,但是由于其强大的功能与众多的

NOR Flash擦写和原理分析 (二)

Nor Flash上电后处于数据读取状态(Reading Array Data).此状态可以进行正常的读.这和读取SDRAM/SRAM/ROM一样.(要是不一样的话,芯片上电后如何从NorFlash中读取启动代码.~) 一般再对Flash进行操作前都要读取芯片信息比如设备ID号.这样做的主要目的是为了判断自己写的程序是否支持该设备. Nor Flash支持2种方式获取ID号.一种是编程器所用的方法需要高电压(11.5V-12.5V).另一种方法就是所谓的in-system方法,就是在系统中通过N

第一次作业:基于Linux操作系统深入源码进程模型分析

1.Linux操作系统的简易介绍 Linux系统一般有4个主要部分:内核.shell.文件系统和应用程序.内核.shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序.管理文件并使用系统. (1)内核 内核是操作系统的核心,具有很多最基本功能,如虚拟内存.多任务.共享库.需求加载.可执行程序和TCP/IP网络功能.Linux内核的模块分为以下几个部分:存储管理.CPU和进程管理.文件系统.设备管理和驱动.网络通信.系统的初始化和系统调用等. (2)shell shell是系统

【数据结构】循环链表&amp;&amp;双向链表详解和代码实例

喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 循环链表 1.1 什么是循环链表? 前面介绍了单链表,相信大家还记得相关的概念.其实循环链表跟单链表也没有差别很多,只是在某些细节上的处理方式会稍稍不同. 在此之前,大家可以先思考一个问题:单链表中,要找到其中某个节点只需要从头节点开始遍历链表即可,但是有些时候我们的想法是,能不能从任意节点开始遍历,也能找到我们需要的那个节点呢? 其实啊,这个实现也很简单自然,把整个链表串成一个环问题就迎刃而解了.所以,关于循环链表,

Leetcode 344:Reverse String 反转字符串(python、java)

Leetcode 344:Reverse String 反转字符串 公众号:爱写bug Write a function that reverses a string. The input string is given as an array of characters char[]. Do not allocate extra space for another array, you must do this by modifying the input array in-place wit

利用Python库,把Python当PS用!

给大家带来一篇关于PIL的文章,PIL全称是Python Image Library,顾名思义,是用来做图像处理的.用这个库,可以实现很多PS里的效果,比如像图片模糊.寻找轮廓.边缘检测等等.我们来看看具体怎么做到的呢?? PS作为世界四大发明之一可以说被广大网友用到了极致,只有你想不到的没有我P不了的,任何正经的图片在都可以变成搞笑图片(比如下图)当然也可以用ps做一点正经的事情. 作为一个爱折腾的程序猿能用代码的解决的事情绝对不会用其他的方式,Python可以打飞机,人工降雪,那么p个图对于

开发好玩吧系统方案操作

开发好玩吧系统,找蔡生:191电5743微0737,好玩吧系统开发费用,好玩吧软件开发,好玩吧平台定制,好玩吧系统开发,开发好玩吧APP,好玩吧系统开发案例,开发好玩吧app案例,现成好玩吧软件源码 区块链+可以说是2019年很火的营销模式,现在市面上基于智能合约等创新技术而生出很多好玩的商业模式,好玩吧APP系统开发就是其中一个,打造一个区块链+游戏挖坑创新平台, 一.好玩吧APP系统开发的钻石矿机有什么用? 好玩吧APP系统开发不卖矿机,只开放用钻石兑换矿机,玩家玩游戏送矿机. 1.我的矿机

好玩吧系统开发怎么操作

开发好玩吧系统,找蔡生:191电5743微0737,好玩吧系统开发费用,好玩吧软件开发,好玩吧平台定制,好玩吧系统开发,开发好玩吧APP,好玩吧系统开发案例,开发好玩吧app案例,现成好玩吧软件源码 区块链+可以说是2019年很火的营销模式,现在市面上基于智能合约等创新技术而生出很多好玩的商业模式,好玩吧APP系统开发就是其中一个,打造一个区块链+游戏挖坑创新平台, 一.好玩吧APP系统开发的钻石矿机有什么用? 好玩吧APP系统开发不卖矿机,只开放用钻石兑换矿机,玩家玩游戏送矿机. 1.我的矿机

【好玩的棋盘游戏】编写一个玩家操作的函数和电脑能够操作的两人棋盘游戏,哪边有三个相连的胜出

#include <stdio.h> #include <stdlib.h> char arr[3][3]; void print() { int t; for(t=0;t<3;t++) { printf("%c|%c|%c|",arr[t][0],arr[t][1],arr[t][2]); printf("\n_|_|_|\n"); } } void init() { int i,j; for(i=0;i<3;i++) { fo