• Java常用集合解析


    目录

    1.List集合

    2.Set集合

    3.Mep集合


     

    1.List集合

    特点:元素有序,可重复。

    三种遍历:下标,foie循环,迭代器。

    扩容:
        初始容量10 , 负载因子0.5,扩容增量0.5倍
        新容量 = 原容量 + 原容量 * 0.5  , 如 ArrayList的容量为10,一次扩容后是容量为15

    实现类:ArrayList . LinkedList . Vector . CopyOnWriteArrayList


    ArrayList:1.动态数组,自动扩容。线程不安全。不适合随机增加和删除。

    定义一个数组。如下:

    1. package com.zking.demo.test;
    2. import java.util.ArrayList;
    3. import java.util.Iterator;
    4. import java.util.List;
    5. import org.junit.Before;
    6. import org.junit.Test;
    7. public class ListDemo {
    8. private List<Integer> list;
    9. @Before
    10. public void Demo01() {
    11. list=new ArrayList<Integer>();
    12. list.add(1);
    13. list.add(2);
    14. list.add(3);
    15. list.add(3);
    16. list.add(4);
    17. list.add(5);
    18. }
    19. }

     ArrayList正确删除元素的三种方法:

    第一种(for循环):

    1. @Test
    2. public void Demo02() {
    3. System.out.println("删除前:"+list);
    4. for (int i = list.size()-1; i >=0 ; i--) {
    5. if(list.get(i)==3) {
    6. Integer remove = list.remove(i);
    7. }
    8. }
    9. System.out.println("删除后:"+list);
    10. }

    第二种(迭代器):

    1. @Test
    2. public void Demo03() {
    3. System.out.println("删除前:"+list);
    4. Iterator<Integer> iterator = list.iterator();
    5. while(iterator.hasNext()) {
    6. if(iterator.next()==3) {
    7. iterator.remove();
    8. }
    9. }
    10. System.out.println("删除后:"+list);
    11. }

    第三种(for循环):

    1. @Test
    2. public void Demo04() {
    3. System.out.println("删除前:"+list);
    4. for (int i = 0; i < list.size(); i++) {
    5. if(list.get(i)==3) {
    6. list.remove(i--);
    7. }
    8. }
    9. System.out.println("删除后:"+list);
    10. }

    结果是:

    ArrayList错误删除方式:

    第一种(相邻且相同无法删除):

    1. @Test
    2. public void Demo05() {
    3. System.out.println("删除前:"+list);
    4. for (int i = 0; i < list.size(); i++) {
    5. if(list.get(i)==3) {
    6. list.remove(i);
    7. }
    8. }
    9. System.out.println("删除后:"+list);
    10. }

    结果是:

    看上面这张图,还有个元素3没有删除掉,出现这个错误是因为在删除第一个元素3之后后面的元素会挤上来,下标随之改变-1,相邻的第二个3就从下标为3变成了下标为2,从而第二个元素3就没有删掉。

    第二种方式(有重复元素无法删除):

    1. @Test
    2. public void Demo06() {
    3. System.out.println("删除前:"+list);
    4. for (Integer integer : list) {
    5. if(integer==3) {
    6. list.remove(integer);
    7. }
    8. }
    9. System.out.println("删除后:"+list);
    10. }

    第三种方式(有重复元素无法删除):

    1. Iterator<Integer> it=list.iterator();
    2. while(it.hasNext()){
    3. Integer value=it.next();
    4. if(value==3){
    5. list.remove(value);
    6. }
    7. }

    结果都是:

    第四种方式(根据下标删除): 

    1. @Test
    2. public void Demo07() {
    3. System.out.println("删除前:"+list);
    4. list.remove(1);
    5. System.out.println("删除后:"+list);
    6. }

    结果是:

     LinkedList
        LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部
        线程不安全
        LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)
        以双向链表实现,链表无容量限制,允许元素为null,线程不安全
        适合做随机的增加或删除

    Vector
        线程安全
        并行性能慢,不建议使用 

    CopyOnWriteArrayList
        写时复制
        线程安全
        适合于读多,写少的场景
        写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array
        比Vector性能高
        最终一致性
        实现了List接口,使用方式与ArrayList类似 

    2.Set集合

    特点:无序,不可重复。

    扩容: 初始容量16,负载因子0.75,扩容增量1倍

    实现类:HashSet . TreeSet

     HashSet:

    1.不重复,无序,允许空值。:依据对象的hashcode来确定该元素是否存在

    2.底层是hashMap实现。

    3.线程不安全

    4.性能参数:初始容量,负载因子
        默认值: 初始容量16,负载因子0.75
        示例:new HashSet<>(20, 0.5f);

    遍历:fore循环,迭代器。

    实体类:

    1. package com.zking.demo.entity;
    2. public class Student {
    3. private Integer id;
    4. private String name;
    5. private Integer age;
    6. public Student() {
    7. // TODO Auto-generated constructor stub
    8. }
    9. public Student(Integer id, String name, Integer age) {
    10. super();
    11. this.id = id;
    12. this.name = name;
    13. this.age = age;
    14. }
    15. public Integer getId() {
    16. return id;
    17. }
    18. public void setId(Integer id) {
    19. this.id = id;
    20. }
    21. public String getName() {
    22. return name;
    23. }
    24. public void setName(String name) {
    25. this.name = name;
    26. }
    27. public Integer getAge() {
    28. return age;
    29. }
    30. public void setAge(Integer age) {
    31. this.age = age;
    32. }
    33. @Override
    34. public String toString() {
    35. return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
    36. }
    37. @Override
    38. public int hashCode() {
    39. final int prime = 31;
    40. int result = 1;
    41. result = prime * result + ((age == null) ? 0 : age.hashCode());
    42. result = prime * result + ((id == null) ? 0 : id.hashCode());
    43. result = prime * result + ((name == null) ? 0 : name.hashCode());
    44. return result;
    45. }
    46. @Override
    47. public boolean equals(Object obj) {
    48. if (this == obj)
    49. return true;
    50. if (obj == null)
    51. return false;
    52. if (getClass() != obj.getClass())
    53. return false;
    54. Student other = (Student) obj;
    55. if (age == null) {
    56. if (other.age != null)
    57. return false;
    58. } else if (!age.equals(other.age))
    59. return false;
    60. if (id == null) {
    61. if (other.id != null)
    62. return false;
    63. } else if (!id.equals(other.id))
    64. return false;
    65. if (name == null) {
    66. if (other.name != null)
    67. return false;
    68. } else if (!name.equals(other.name))
    69. return false;
    70. return true;
    71. }
    72. }
    1. //fore循环遍历
    2. @Test
    3. public void demo03() {
    4. Set<Student> set =new HashSet<>();
    5. set.add(new Student(1, "xm", 18));
    6. set.add(new Student(1, "xm", 18));
    7. set.add(new Student(2, "xh", 19));
    8. set.add(new Student(2, "xh", 19));
    9. set.add(new Student(3, "xl", 20));
    10. set.add(new Student(3, "xl", 20));
    11. for (Student student : set) {
    12. System.out.println(student);
    13. }
    14. }
    15. //迭代器遍历
    16. @Test
    17. public void demo04() {
    18. Set<Student> set =new HashSet<>();
    19. set.add(new Student(1, "xm", 18));
    20. set.add(new Student(1, "xm", 18));
    21. set.add(new Student(2, "xh", 19));
    22. set.add(new Student(2, "xh", 19));
    23. set.add(new Student(3, "xl", 20));
    24. set.add(new Student(3, "xl", 20));
    25. Iterator ite=set.iterator();
    26. while(ite.hasNext()) {
    27. System.out.println(ite.next());
    28. }
    29. }

    结果是:

    这个结果是因为Student学生实体实现了 hashCode()  ,  equals()方法。

    如果不实现这两个方法,那么就不会自动去重。则就是如下图:

    如果自定义实体类对象的属性有很多,20个、30个等等,那么我们只需要重写equals和hashcode方法里面特定的几个属性,只要足够判断去重就可以了。 

    比如上面Student类是三个属性,但判断学生类去重只需要重写hashcode和equals方法中的一个编号就可以了。

    也就是如下实体类代码:

    1. package com.zking.demo.entity;
    2. public class Student {
    3. private Integer id;
    4. private String name;
    5. private Integer age;
    6. public Student() {
    7. // TODO Auto-generated constructor stub
    8. }
    9. public Student(Integer id, String name, Integer age) {
    10. super();
    11. this.id = id;
    12. this.name = name;
    13. this.age = age;
    14. }
    15. public Integer getId() {
    16. return id;
    17. }
    18. public void setId(Integer id) {
    19. this.id = id;
    20. }
    21. public String getName() {
    22. return name;
    23. }
    24. public void setName(String name) {
    25. this.name = name;
    26. }
    27. public Integer getAge() {
    28. return age;
    29. }
    30. public void setAge(Integer age) {
    31. this.age = age;
    32. }
    33. @Override
    34. public String toString() {
    35. return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
    36. }
    37. @Override
    38. public int hashCode() {
    39. final int prime = 31;
    40. int result = 1;
    41. result = prime * result + ((id == null) ? 0 : id.hashCode());
    42. return result;
    43. }
    44. @Override
    45. public boolean equals(Object obj) {
    46. if (this == obj)
    47. return true;
    48. if (obj == null)
    49. return false;
    50. if (getClass() != obj.getClass())
    51. return false;
    52. Student other = (Student) obj;
    53. if (id == null) {
    54. if (other.id != null)
    55. return false;
    56. } else if (!id.equals(other.id))
    57. return false;
    58. return true;
    59. }
    60. }

     TreeSet
        是一个包含有序的且没有重复元素的集合
        作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
        TreeSet是基于TreeMap实现的

    思考:list集合怎么去重?

            答案:借助set集合。首先先将list集合对象通过set集合的构造函数转化为set集合对象,再通过同样的操作将set集合对象通过list集合的构造函数转化为list集合对象就可以了。

    例如:

    1. package com.zking.demo.test;
    2. import java.util.ArrayList;
    3. import java.util.HashSet;
    4. import java.util.List;
    5. import org.junit.Before;
    6. import org.junit.Test;
    7. public class Set {
    8. private List<Integer> list=new ArrayList<Integer>();
    9. @Before
    10. public void demo01() {
    11. list.add(1);
    12. list.add(1);
    13. list.add(2);
    14. list.add(3);
    15. list.add(3);
    16. }
    17. @Test
    18. public void demo02() {
    19. List<Integer> list=new ArrayList<>(new HashSet<>(this.list));
    20. System.out.println(list);
    21. }
    22. }

     Set集合想要排序,就要借助它的实现类treeSet来进行排序。(默认是自然排序)

    1. @Test
    2. public void demo05() {
    3. Set<Integer> set=new TreeSet<>();
    4. set.add(1);
    5. set.add(3);
    6. set.add(4);
    7. set.add(6);
    8. set.add(2);
    9. set.add(5);
    10. for (Integer integer : set) {
    11. System.out.println(integer);
    12. }
    13. }

    结果是:

    如果想要倒序排序就需要用到比较器Comparator,可以实现也可以通过构造方法传入。

    下面是通过构造方法:

    1. @Test
    2. public void demo05() {
    3. Set<Integer> set=new TreeSet<>(new Comparator<Integer>() {
    4. @Override
    5. public int compare(Integer o1, Integer o2) {
    6. // TODO Auto-generated method stub
    7. return o2-o1;
    8. }
    9. });
    10. set.add(1);
    11. set.add(3);
    12. set.add(4);
    13. set.add(6);
    14. set.add(2);
    15. set.add(5);
    16. for (Integer integer : set) {
    17. System.out.println(integer);
    18. }
    19. }

    结果就是:

    那如果是对象呢?该通过什么方式排序?

    就比如Student学生类,通过构造方法传入比较器之后,通过对象的属性来比较大小进行排序

    如下通过年龄来进行排序:

    1. @Test
    2. public void demo06() {
    3. Set<Student> set=new TreeSet<>(new Comparator<Student>() {
    4. @Override
    5. public int compare(Student o1, Student o2) {
    6. return o2.getAge()-o1.getAge();//通过学生的年龄来进行排序。
    7. }
    8. });
    9. set.add(new Student(1, "xm", 18));
    10. set.add(new Student(2, "xh", 19));
    11. set.add(new Student(3, "xl", 20));
    12. set.add(new Student(4, "xx", 21));
    13. Iterator ite=set.iterator();
    14. while(ite.hasNext()) {
    15. System.out.println(ite.next());
    16. }
    17. }

    结果是:

     但有一个小细节需要注意,如果出现同样年龄的人,就会漏掉一个学生。所以我们得在做一个判断,当学生的年龄相同时,用一个特有属性再进行排序即可。

    如下:

    1. @Test
    2. public void demo06() {
    3. Set<Student> set=new TreeSet<>(new Comparator<Student>() {
    4. @Override
    5. public int compare(Student o1, Student o2) {
    6. if(o2.getAge()==o1.getAge()) {
    7. return o2.getId()-o1.getId();//再通过编号进一步排序。
    8. }
    9. return o2.getAge()-o1.getAge();//通过学生的年龄来进行排序。
    10. }
    11. });
    12. set.add(new Student(1, "xm", 18));
    13. set.add(new Student(2, "xh", 19));
    14. set.add(new Student(3, "xl", 20));
    15. set.add(new Student(4, "xx", 20));
    16. Iterator ite=set.iterator();
    17. while(ite.hasNext()) {
    18. System.out.println(ite.next());
    19. }

    结果是:

     这样就不会漏掉数据了。

    就比如Student学生类,通过实现比较器接口,通过对象的属性来比较大小进行排序

    如下通过年龄来进行排序:

    实体类:

    1. package com.zking.demo.entity;
    2. import java.util.Comparator;
    3. public class Student implements Comparable<Student> {
    4. private Integer id;
    5. private String name;
    6. private Integer age;
    7. public Student() {
    8. // TODO Auto-generated constructor stub
    9. }
    10. public Student(Integer id, String name, Integer age) {
    11. super();
    12. this.id = id;
    13. this.name = name;
    14. this.age = age;
    15. }
    16. public Integer getId() {
    17. return id;
    18. }
    19. public void setId(Integer id) {
    20. this.id = id;
    21. }
    22. public String getName() {
    23. return name;
    24. }
    25. public void setName(String name) {
    26. this.name = name;
    27. }
    28. public Integer getAge() {
    29. return age;
    30. }
    31. public void setAge(Integer age) {
    32. this.age = age;
    33. }
    34. @Override
    35. public String toString() {
    36. return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
    37. }
    38. @Override
    39. public int hashCode() {
    40. final int prime = 31;
    41. int result = 1;
    42. result = prime * result + ((id == null) ? 0 : id.hashCode());
    43. return result;
    44. }
    45. @Override
    46. public boolean equals(Object obj) {
    47. if (this == obj)
    48. return true;
    49. if (obj == null)
    50. return false;
    51. if (getClass() != obj.getClass())
    52. return false;
    53. Student other = (Student) obj;
    54. if (id == null) {
    55. if (other.id != null)
    56. return false;
    57. } else if (!id.equals(other.id))
    58. return false;
    59. return true;
    60. }
    61. @Override
    62. public int compareTo(Student o) {
    63. if(o.getAge()==this.getAge()) {
    64. return o.getId()-this.getId();
    65. }
    66. return o.getAge()-this.getAge();
    67. }
    68. }

     测试类:

    1. @Test
    2. public void demo06() {
    3. Set<Student> set=new TreeSet<>();
    4. set.add(new Student(1, "xm", 18));
    5. set.add(new Student(2, "xh", 19));
    6. set.add(new Student(3, "xl", 20));
    7. set.add(new Student(4, "xx", 20));
    8. Iterator ite=set.iterator();
    9. while(ite.hasNext()) {
    10. System.out.println(ite.next());
    11. }
    12. }

    结果是一样的:

    如果实体类实现了比较器接口Comparabled,而测试方法通过构造方法传入了构造器,那么是构造方法的生效。

    3.Mep集合

    特点:
        无序,键值对,键不能重复,值可以重复,
        键重复则覆盖,没有继承Collection接口

    扩容:初始容量16,负载因子0.75,扩容增量1倍

    遍历
        先获取所有键的Set集合,再遍历(通过键获取值)
        取出保存所有Entry的Set,再遍历此Set即可

     hashMap:

    第一种遍历方式,通过keySet()获取所有键Set集合,然后遍历再得到值。

    如下:

    1. @Test
    2. public void demo01() {
    3. map.put("1", "小明");
    4. map.put("2", "小明2");
    5. map.put("3", "小明3");
    6. map.put("4", "小明4");
    7. Iterator<String> iterator = map.keySet().iterator();
    8. while(iterator.hasNext()) {
    9. String key = iterator.next();
    10. Object value = map.get(key);
    11. System.out.println(value);
    12. }
    13. }

    结果是:

    第二种遍历方式:通过entrySet()方法,得到所有键值对对象的Set集合,然后通过迭代器遍历分别得到键和值。

    如下:

    1. @Test
    2. public void demo02() {
    3. map.put("1", "小明");
    4. map.put("2", "小明2");
    5. map.put("3", "小明3");
    6. map.put("4", "小明4");
    7. Set<Entry<String,Object>> entrySet = map.entrySet();
    8. Iterator<Entry<String, Object>> iterator = entrySet.iterator();
    9. while(iterator.hasNext()) {
    10. Entry<String, Object> next = iterator.next();
    11. System.out.println("key:"+next.getKey()+"-----"+"value:"+next.getValue());
    12. }

     结果是:

     

    HashTable
        线程安全,不太常用 ,效率慢。

     ConcurrentHashMap
        线程安全,比HashTable性能高

    TreeMap
        key值按一定的顺序排序
        添加或获取元素时性能较HashMap慢
            因为需求维护内部的红黑树,用于保证key值的顺序 

    代码如下:

    1. @Test
    2. public void demo03() {
    3. Map<String, Object> treeMap=new TreeMap<>(new Comparator<String>() {
    4. @Override
    5. public int compare(String o1, String o2) {
    6. // TODO Auto-generated method stub
    7. return o2.compareTo(o1);
    8. }
    9. });
    10. treeMap.put("1", "小明");
    11. treeMap.put("2", "小明2");
    12. treeMap.put("3", "小明3");
    13. treeMap.put("4", "小明4");
    14. Set<Entry<String,Object>> entrySet = treeMap.entrySet();
    15. Iterator<Entry<String, Object>> iterator = entrySet.iterator();
    16. while(iterator.hasNext()) {
    17. Entry<String, Object> next = iterator.next();
    18. System.out.println("key:"+next.getKey()+"-----"+"value:"+next.getValue());
    19. }
    20. }

    结果:

     默认是升序排序,而上面o1和o2调货了位置,则变成了降序。

    LinkedHashMap:

    LinkedHashMap是有序的,且默认为插入顺序
        当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了

    代码如下:

    1. @Test
    2. public void demo04() {
    3. Map<String, String> linkedHashMap = new LinkedHashMap<>();
    4. linkedHashMap.put("name1", "josan1");
    5. linkedHashMap.put("name2", "josan2");
    6. linkedHashMap.put("name3", "josan3");
    7. Set<Entry<String, String>> set = linkedHashMap.entrySet();
    8. Iterator<Entry<String, String>> iterator = set.iterator();
    9. while(iterator.hasNext()) {
    10. Entry entry = iterator.next();
    11. String key = (String) entry.getKey();
    12. String value = (String) entry.getValue();
    13. System.out.println("key:" + key + ",value:" + value);
    14. }
    15. }

     

  • 相关阅读:
    ELK 使用 metricbeat监控数据
    用Python写一个去文档水印的算法
    linux查看端口是否开放
    Linux下socket例子(c/c++)
    苹果起诉以色列安全公司NSO,间谍软件是侵犯隐私还是打击犯罪?
    水循环原理VR实景教学课件开发
    数组与字符串的相互转换
    Smartbi融入“多维建模”能力,满足一站式BI需求
    python-(6-3-2)爬虫---requests入门(基于post请求)
    Projectively extended real line
  • 原文地址:https://blog.csdn.net/m0_64719055/article/details/125502186