这里主要谈下Java集合在使用中容易被忽略、又容易出现的两个“坑”,一个是集合与数组互相转换,另一个是集合遍历删除。主要通过代码演示。

  一.集合与数组互相转换中的“坑”  

  1. //Test1.java
  2. package com.itszt.test0419;
  3.  
  4. import java.util.ArrayList;
  5. import java.util.Arrays;
  6. import java.util.Collections;
  7. import java.util.List;
  8. /**
  9. * 集合与数组互相转换,含list集合元素反序排列
  10. */
  11. public class Test1 {
  12. public static void main(String[] args) {
  13. //一个集合对象
  14. ArrayList<String> list=new ArrayList<>();
  15. list.add("a");
  16. list.add("b");
  17. list.add("c");
  18. list.add("d");
  19. list.add("e");
  20. //集合元素正反序转换
  21. System.out.println("正序---list = " + list.toString());
  22. Collections.reverse(list);
  23. System.out.println("反序---list = " + list.toString());
  24. Collections.reverse(list);
  25. System.out.println("恢复初始状态---list"+list);
  26. //(1)集合转数组
  27. Object[] listArray1 = list.toArray();//方法1
  28. System.out.println("方法1---listArray1 = " + Arrays.toString(listArray1));
  29. String[] listArray2 = list.toArray(new String[list.size()]);//方法2
  30. System.out.println("方法2---listArray2 = " + Arrays.toString(listArray2));
  31. String[] listArray3=new String[list.size()];//方法3
  32. for(int i=0;i<list.size();i++){
  33. listArray3[i]=list.get(i);
  34. }
  35. System.out.println("方法3---listArray3 = " + Arrays.toString(listArray3));
  36. //(2)数组转集合
  37. List<Object> asList = Arrays.asList(listArray1);
  38. /*
  39. 此时返回的ArrayList是Arrays的一个私有静态内部类,
  40. 可以遍历查询,但是不可以像普通集合那样增删元素
  41. */
  42. System.out.println("asList = " + asList.toString());
  43. /*
  44. asList.add("f");
  45. asList.remove("a");
  46. //若增删元素,均会抛出异常 java.lang.UnsupportedOperationException
  47. */
  48. //下述方法成功地将数组转化为集合
  49. ArrayList arrayList = new ArrayList<>(asList);
  50. arrayList.add("f");
  51. arrayList.remove("a");
  52. System.out.println("arrayList = " + arrayList.toString());
  53. }
  54. }

  二.集合遍历删除中的“坑”  

  1. //Test2.java
  2. package com.itszt.test0419;
  3. import java.util.ArrayList;
  4. import java.util.Iterator;
  5. /**
  6. * 集合遍历删除中的坑
  7. * 推荐对JAVA集合进行遍历删除时用迭代器
  8. */
  9. public class Test2 {
  10. public static void main(String[] args) {
  11. //一个集合对象
  12. ArrayList<String> list=new ArrayList<>();
  13. list.add("a");
  14. list.add("b");
  15. list.add("c");
  16. list.add("d");
  17. list.add("e");
  18.  
  19. //下面是错误的遍历删除方式,抛出异常:java.util.ConcurrentModificationException
  20. /*for(String s:list){
  21. list.remove(s);
  22. }*/
  23. //其实,上述代码在执行时,会转换成迭代器执行,但删除操作却用了错误的方法,如下所示:
  24. /*for(Iterator<String> it=list.iterator();it.hasNext();){
  25. String next = it.next();
  26. list.remove(next);
  27. }*/
  28.  
  29. //若将上述代码予以改写,就可以正常执行:
  30. /*for(Iterator<String> it=list.iterator();it.hasNext();){
  31. it.remove();
  32. }
  33. System.out.println("list = " + list.size());*/
  34.  
  35. /*
  36. 另外,下述方式不会报异常,但只能遍历删除部分元素。
  37. 这是因为:该方法中有一个严重的错误。
  38. 当一个元素被删除时,列表的大小缩小并且下标变化,
  39. 所以当你想要在一个循环中用下标删除多个元素的时候,它并不会正常生效。
  40. */
  41. /*for(int i=0;i<list.size();i++){
  42. list.remove(i);
  43. }
  44. System.out.println("list = " +
  45. list.size()+"---"+
  46. list.toString());*/
  47.  
  48. //下述方法可以清空集合内的所有元素
  49. /*list.clear();
  50. System.out.println("list = " +list.size());*/
  51.  
  52. //下述方式可以正确地删除指定内容的元素
  53. /*for(int i=0;i<list.size();i++){
  54. if("a".equals(list.get(i))){
  55. list.remove(i);
  56. }
  57. }
  58. System.out.println("list = " + list.toString());*/
  59.  
  60. /**
  61. * 那么,为什么List集合使用迭代后,就不能再用集合自身的删除方法list.remove(i)了呢?
  62. * 这是因为,ArrayList与Iterator混合使用时会导致各自的状态出现不一样,最终出现异常。
  63. * ArrayList采用size属性来维护自已的状态,而Iterator采用cursor来来维护自已的状态。
  64. * 当size出现变化时,cursor并不一定能够得到同步,除非这种变化是Iterator主动导致的。
  65. * Iterator.remove方法导致ArrayList列表发生变化时,会自动更新cursor来同步这一变化。
  66. * 但其他方式导致的ArrayList变化,Iterator是无法感知的。
  67. * ArrayList不会主动通知Iterator,这将有损效率。
  68. * 为了防止状态不一致可能引发的无法设想的后果,
  69. * Iterator会经常做checkForComodification检查,以防有变。
  70. * 如果有变,则以异常抛出,所以就抛出了上面的异常:
  71. * java.util.ConcurrentModificationException
  72. * 再来比较下面两种遍历删除方法:
  73. */
  74.  
  75. //错误的删除方法 抛出异常:java.util.ConcurrentModificationException
  76. /*for(String s:list){
  77. if("a".equals(s)){
  78. list.remove(s);
  79. }
  80. }
  81. System.out.println("list = " + list.toString());*/
  82.  
  83. //正确的删除方法
  84. /*for(Iterator<String> it=list.iterator();it.hasNext();){
  85. if("a".equals(it.next())){
  86. it.remove();
  87. }
  88. }
  89. System.out.println("list = " + list.toString());*/
  90. /**
  91. * 上述两种方法的不同结果是因为:
  92. *.next()必须在.remove()之前调用。
  93. * 在一个foreach循环中,编译器会使.next()在删除元素之后被调用,
  94. * 因此就会抛出ConcurrentModificationException异常。
  95. * 总之:
  96. * Iterator 支持从源集合中安全地删除对象,
  97. * 只需在 Iterator 上调用 remove() 即可。
  98. * 这样做的好处是可以避免 ConcurrentModificationException ,
  99. * 这个异常顾名思意:当打开 Iterator 迭代集合时,同时又在对集合进行修改。
  100. * 为此,在对集合迭代时删除或添加元素时,调用 Iterator 的remove() 方法是个安全的做法。
  101. */
  102. }
  103. }

Java集合里的一些“坑”的更多相关文章

  1. Java集合源码学习(一)集合框架概览

    >>集合框架 Java集合框架包含了大部分Java开发中用到的数据结构,主要包括List列表.Set集合.Map映射.迭代器(Iterator.Enumeration).工具类(Array ...

  2. Java集合源码学习(一)Collection概览

    1.集合框架 Java集合框架包含了大部分Java开发中用到的数据结构,主要包括List列表.Set集合.Map映射.迭代器(Iterator.Enumeration).工具类(Arrays.Coll ...

  3. java 集合(Set1)

    ----------------|Collection(为什么要画这个图?学多了之后该忘了) --------------------------|List --------------------- ...

  4. 【原创】这道Java基础题真的有坑!我也没想到还有续集。

    前情回顾 自从我上次发了<这道Java基础题真的有坑!我求求你,认真思考后再回答.>这篇文章后.我通过这样的一个行文结构: 解析了小马哥出的这道题,让大家明白了这题的坑在哪里,这题背后隐藏 ...

  5. Java 集合看这一篇就够了

    大家好,这里是<齐姐聊数据结构>系列之大集合. 话不多说,直接上图: Java 集合,也称作容器,主要是由两大接口 (Interface) 派生出来的: Collection 和 Map ...

  6. Java集合【9】-- Vector源码解析

    目录 1.Vector介绍 2. 成员变量 3. 构造函数 4. 常用方法 4.1 增加 4.2 删除 4.3 修改 4.4 查询 4.5 其他常用函数 4.6 Lambda表达式相关的方法 4.7 ...

  7. java 集合 + 常见面试题

    1.1. 集合概述 1.1.1. Java 集合概览 从下图可以看出,在 Java 中除了以 Map 结尾的类之外, 其他类都实现了 Collection 接口. 并且,以 Map 结尾的类都实现了 ...

  8. 《面试补习》- Java集合知识梳理

    一.ArrayList ArrayList 底层数据结构为 动态数组 ,所以我们可以将之称为数组队列. ArrayList 的依赖关系: public class ArrayList<E> ...

  9. Java集合精选常见面试题

    前言 博主只是这篇文章的搬运工,为了加强记忆自己梳理了一遍并扩展了部分内容. 集合拓展链接:集合概述&集合之Collection接口 - 至安 - 博客园 (cnblogs.com) Java ...

随机推荐

  1. 降雨量 HYSBZ - 1067(RMQ)

    F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ Login Register 捐赠本站 Notice:1:注册本OJ方式请见ht ...

  2. 【转】Oracle 查询库中所有表名、字段名、表名说明、字段名说明

    转自 :http://gis-conquer.blog.sohu.com/170243422.html 查询所有表名:select t.table_name from user_tables t; 查 ...

  3. CF335F Buy One, Get One Free 贪心

    题意: \(n\)个物品,每个物品有一个价格,买一个高价格的物品,可以选择免费得到一个价格严格低于这个物品的物品.求得到\(n\)个物品的最小代价. 题解: 神仙贪心-- 题目要求求出最小代价,相当于 ...

  4. 【WebAPI】新手入门WebAPI

    一.前言       工作也有一年多了,从进入公司就一直进行BIM(建筑信息模型)C/S产品的研发,平时写的最多的就是Dev WPF.一个偶然的时机,产品需要做支付宝扫码与微信扫码,所以需要了解产品服 ...

  5. 音视频处理之FFmpeg程序的介绍与使用20180302

    一.FFMPEG程序介绍与使用 主要介绍一下ffmpeg工程包含的三个exe的使用方法. 1. FFMPEG程序介绍 1.1.下载 ffmpeg的官方网站是:http://ffmpeg.org/ 下载 ...

  6. makefile使用笔记(二)变量

    By francis_hao    Oct 30,2017   makefile中可以使用变量,变量有多种类型,下面分别介绍 简单变量 简单变量的命名规则和c语言一致. 给变量赋值就表示创建了这个变量 ...

  7. 很好的c++和Python混合编程文章

    c++中嵌入python入门1 本人是用vc2003+python2.5学习的,其它的也应该差不了多少 0. 坏境设置把Python的include/libs目录分别加到vc的include/lib ...

  8. nginx如何配置虚拟主机

    server { listen 80; #listen [::]:80 default_server ipv6only=on; server_name local.presion.caomall.ne ...

  9. Java常量池详解之Integer缓存

    一个Java question,求输出结果   public class IntegerTest { public static void main(String[] args) { objPoolT ...

  10. jquery读取html5的data-属性

    前端代码的工作无非就是接收后端发来的数据,展示到前端页面:又或者,给无数的按钮,图片,段落等绑定各种事件.那么我们在绑定事件是需要拿取HTML页面的元素,以及在拿取的元素给定各式各样的自定义属性.当需 ...