Bootstrap

1️⃣Java中的集合体系学习汇总(List/Map/Set 详解)

目录

01. Java中的集合体系

02. 单列集合体系​

1. Collection系列集合的遍历方式

(1)迭代器遍历(2)增强for遍历​编辑(3)Lambda表达式遍历

 

03.List集合详解

04.Set集合详解

05.总结

Collection系列集合使用场景:​

集合的并发修改异常问题①问题原因②解决办法


01. Java中的集合体系

Java中的集合分为两大类:

  • 单列集合(collection):添加数据时,一次只添加一个数据。数据带有下标

  • 双列集合(Map):在添加数据时,一次要添加一对数据;key和value(键值对)

02. 单列集合体系

单列集合起源于Collection接口,分为List集合和Set集合:

①List接口的三个实现类:ArrayList、LinkedList、Vector(现已弃用);

②List系列集合的特点有:有序、可重复、有索引,有序是指存入的顺序和取出时的顺序是相同的;

③Set接口有两个实现类:HashSet、TreeSet;

④Set系列集合的特点有:无序、不可重复、无索引,取数据时的顺序是随机的。

(1)单列集合顶层接口Collection

常用方法:

注意点:

1.添加元素 add 细节1: 如果我们要往List系列集合中添加数据, 那么方法永远返回true, 因为List系列的是允许元素重复的。 细节2: 如果我们要往Set系列集合中添加数据,如果当前要添加元素不存在,方法返回true,表示添加成功。 如果当前要添加的元素已经存在, 方法返回false,表示添加失败。因为Set系列的集合不允许重复。

2.删除 remove 细节1: 因为collection里面定义的是共性的方法, 所以此时不能通过索引 进行删除。 只能通过元素名称进行刷除。 细节2: 方法会有一个布尔类型的返回值, 删除成功返回true, 删除失败返回false,如果要除的元素不存在,就会删除失败。

4.判断元素是否包含 contain 细节:底层是依赖equals方法进行判断是否存在的。 所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在java Bean类中,一定要重写equals方法

源码查看方法: 方法一:选中contains()方法,Ctrl+B跟进,进入到Collection接口中的源码; 方法二:选中contains()方法,右键,选择Go to --> implements 然后选择对应的实现类

1. Collection系列集合的遍历方式

(1)迭代器遍历

迭代器Iterator简介:

代码示例:

//1.创建集合并添加元素
Collection<String> coll = new ArrayList<>();
​
coll.add("一");
coll.add("二");
coll.add("三");
coll.add("四");
coll.add("五");
coll.add("六");
​
//2.通过集合获取迭代器,迭代器就好比一个箭头,刚获取时默认指向集合首个元素
Iterator it = coll.iterator();
while (it.hasNext()){
    Object str = it.next();
    System.out.println(str);
}

迭代器使用注意点:

  • 当指针已经指向集合末尾时(如下图),继续调用next( )方法会报错误:NoSuchElementException

  • 迭代器遍历完毕后,指针不会自动复位;下次再遍历时需要再创建一个迭代器对象。

  • 在每次遍历中,next( )方法通常只调用一次,并用一个变量接收返回的元素;(因为每调用一次next( )方法,指针就会向后移动一位,所以每移动一次就要判断一下是否已经指向末尾了)

  • 迭代器遍历时,不能用集合的方法进行增加或删除。否则会引发并发修改异常:ConcurrentModificationException

那么如何在遍历集合时删除集合中元素呢?方法如下:

        使用Iterator.remove() 最安全和推荐的方法是使用迭代器的remove()方法,该方法专为遍历期间的安全删除设计。

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    if ("B".equals(element)) {
        iterator.remove();
    }
}
System.out.println(list); // 输出: [A, C]

优点:不抛异常,适用于多种集合(List、Set等)。

缺点:代码较为冗长,需要显式使用迭代器。

原文链接:java中如何在集合遍历过程中删除元素(5种方法对比、案例、常见的错误及其后果)_java集合删除元素-CSDN博客

(2)增强for遍历

        (小tips:在IDEA中快速打出增强for结构的写法:集合或数组名.for + Enter

        注意:增强for的底层是用迭代器实现的,在遍历时,也不能直接用集合的方法对元素进行增加或删除。否则会引发并发修改异常ConcurrentModificationException

(3)Lambda表达式遍历

 示例代码 :

 public static void main(String[] args) {
        Collection<Object> coll = new ArrayList<>();
        coll.add("张三");
        coll.add("李四");
        coll.add(456);
        coll.add(789);
​
//        for (Object o : coll) {
//            System.out.println(o);
//        }
​
        //常规写法
        coll.forEach(new Consumer<Object>() {
            @Override
            public void accept(Object o) {
                System.out.println(o);
            }
        });
​
        //结合Lambda表达式写法
        coll.forEach((o) -> {
            System.out.println(o);
        });
        //再次简化
        coll.forEach(o->System.out.println(o));
        //结合方法引用,且前后参数一样时,再次简化
        coll.forEach(System.out::println);
​
​
 }

03.List集合详解

由于篇幅过长,为方便大家浏览,这部分内容单独开了一片博客:

Java基础进阶——List集合详解(看这一篇就够了,详解)-CSDN博客list集合属于Java集合体系中的单列集合,继承于父类Collection,如果你对Collection不了解,可以先看这篇文章1️⃣Java中的集合体系学习汇总(List/Map/Set 详解)-CSDN博客细节1: 如果我们要往List系列集合中添加数据, 那么方法永远返回true, 因为List系列的是允许元素重复的。细节2: 方法会有一个布尔类型的返回值, 删除成功返回true, 删除失败返回false,如果要除的元素不存在,就会删除失败。https://blog.csdn.net/Future_yzx/article/details/145159651?sharetype=blogdetail&sharerId=145159651&sharerefer=PC&sharesource=Future_yzx&spm=1011.2480.3001.8118

04.Set集合详解

Java基础进阶—Set集合详解(HashSet、LinkedHashset、TreeSet看这一篇就够了)-CSDN博客LinkedHashSet是HashSet实现类的子类,该集合中的数据是有序的(指添加数据的顺序和获取数据的顺序一致)TreeSet实现类,该集合具有排序功能,向其中存入的数据默认按升序的顺序排序Set系列集合常用方法基本都是父接口Collection提供的,没有特有方法。https://blog.csdn.net/Future_yzx/article/details/145160311?sharetype=blogdetail&sharerId=145160311&sharerefer=PC&sharesource=Future_yzx&spm=1011.2480.3001.8118

 05.总结

 

Collection系列集合使用场景:

 

集合的并发修改异常问题

  • 当我们使用迭代器遍历集合,并删除集合中某些数据时程序就会报错;
    (错误代码如下:)

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王老二");
        list.add("王五");
        list.add("李逵");
        list.add("李世华");
    ​
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String str = it.next();
            if (str.contains("李")){
                list.remove(str);
            }
        }
    }

程序报的异常:

Exception in thread "main" java.util.ConcurrentModificationException

如果我们不用迭代器,用普通for循环来进行相同操作也会有问题;
(错误示例代码:)

//用普通for循环来进行演示:
public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("李四");
    list.add("李老二");
    list.add("王五");
    list.add("李逵");
    list.add("李世华");
​
    System.out.println("遍历前:"+list);
​
    for (int i = 0; i < list.size(); i++) {
        String s = list.get(i);
        if (s.contains("李")){
            list.remove(s);
        }
    }
    System.out.println("遍历后"+list);

输出结果:

遍历前:[张三, 李四, 李老二, 王五, 李逵, 李世华]

遍历后:[张三, 李老二, 王五, 李世华]

我们发现,程序并没有像我们预期的那样(将list集合内所有包含字符"李 "的元素删除掉);

①问题原因:

        当第一次遍历到元素"李四"时,程序会成功删除;由于ArrayList底层是数组实现的,删除元素后,后面元素会向前移动,这就导致下一个元素(李老二)会移动到当前索引的位置;然后i++,直接越过了对"李老二"的判断。

因此,在遍历集合时,每删除当前元素,就会跳过下一个元素的判断;

②解决办法:

●普通for循环的解决办法

①每次移除完数据以后,执行一次i--  ,示例代码:

for (int i = 0; i < list.size(); i++) {
    String s = list.get(i);
    if (s.contains("李")){
        list.remove(s);
        i--;//移除完数据后,执行i--
    }
}

②遍历时,改为从后往前遍历集合,示例代码:

for (int i = list.size()-1; i >= 0; i--) {
    //从后往前倒序遍历集合
    String s = list.get(i);
    if (s.contains("李")){
        list.remove(s);
    }
}

●使用迭代器的解决办法:用迭代器自带的remove方法来删除元素

Iterator<String> it = list.iterator();
while (it.hasNext()){
    String str = it.next();
    if (str.contains("李")){
       //list.remove(str);//会发生修改并发异常
       it.remove();//底层也相当于执行了一次i-- 
    }
}

       

 最后,我们要注意:使用增强for 或 Lambda表达式的方法遍历时,也都会出现并发修改异常,且没有解决办法。

  • 因为增强for的的底层就是迭代器实现的,增强for就是迭代器的简化写法

;