Java的编程之旅46——List集合

1.List集合的特殊方法

List接口是Collection接口的子接口,提供了一系列操作元素的方法。 常见的List集合实现类有ArrayList和LinkedList。ArrayList我们在前面已经介绍过了,这一章中着重介绍一下List集合的特有方法。

        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("world");

        list.add(3,"hahaha"); //通过索引增加元素

        System.out.println(list.remove(3)); //通过索引移除元素,并返回被移除的元素

        System.out.println(list.set(1,"c++"));  //用set函数通过索引修改元素,并返回修改前的元素

        System.out.println(list.get(2));        //用get函数通过索引获取元素,并返回获取到元素的值

        System.out.println(list);

1.增加元素

list.add(index,element) 方法增加元素

 2.删除元素

list.remove(index)

3.修改元素 

list.set(index,element) 

4.获取元素

 list.get(index)

 2.遍历元素

1.for循环遍历

        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("world");

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

2.foreach遍历

        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("world");

        //法二foreach
        for (String li :
                list) {
            System.out.println(li);
        }
        

3.迭代器

        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("world");

        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

该代码段使用ArrayList和Iterator来遍历列表中的元素并打印出来。 首先,代码创建了一个ArrayList对象,并向其中添加了三个字符串元素("hello","java"和"world")。 然后,通过调用list的iterator()方法获取一个Iterator对象。Iterator是一个接口,用于遍历集合中的元素。 接下来,使用while循环和Iterator的hasNext()方法来检查是否还有下一个元素可遍历。 在循环的每次迭代中,使用Iterator的next()方法获取下一个元素,并将其打印出来。 最终,循环结束后,所有元素都被遍历并打印出来。输出结果为: hello java world

4.stream流

        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("world");

        list.stream().forEach(System.out::println);

通过调用list的stream()方法获取一个流(Stream)对象。流是Java 8中引入的一种处理集合数据的方式。 接下来,使用Stream的forEach()方法来迭代每个元素,并使用System.out::println方法引用来打印每个元素。 最终,所有元素都被遍历并打印出来。输出结果为: hello java world

5.lambda表达式

        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("world");

        list.forEach(System.out::println);

使用List的forEach()方法来循环遍历列表中的每个元素。 在forEach()方法中,我们使用System.out::println方法引用来打印每个元素。 最终,所有元素都被遍历并打印出来。输出结果为: hello java world

3.listIterator迭代器

与普通迭代器Iterator相比,listIterator提供了更多的功能。它可以向前和向后遍历集合中的元素,还可以修改集合中的元素,以及获取当前元素的索引。

        List<String> list = new ArrayList<>();
        list.add("JavaSE");
        list.add("MYSQL");
        list.add("JavaWeb");
        list.add("JavaEE");
        ListIterator<String> lt = list.listIterator();
        while (lt.hasNext()){        //正向遍历
            System.out.println(lt.next());
        }

        while (lt.hasPrevious()){
            System.out.println(lt.next());  //逆向遍历
        }

4. 并发性修改异常

并发性修改异常(ConcurrentModificationException)是Java集合框架中的一种异常,表示在迭代器遍历集合元素时,发生了结构性修改。结构性修改指的是改变集合大小或使迭代器失效的操作,如添加、删除或修改元素。

在Java集合框架中,有一些迭代器是通过快速失败机制实现的。这意味着如果在迭代器遍历集合期间进行了结构性修改,会立即抛出ConcurrentModificationException异常,而不是继续遍历。这是为了避免在并发环境下可能出现的不一致性和数据损坏。

例: 在一组列表里增加元素

        List<String> list = new ArrayList<>();
        list.add("JavaSE");
        list.add("MYSQL");
        list.add("JavaWeb");
        list.add("JavaEE");
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String str = it.next();
            if("MYSQL".equals(str)){
                System.out.println("..........");
                list.add("JDBC");
            }
        }

这段代码创建了一个字符串类型的ArrayList,并向其中添加了四个元素。接着,通过iterator()方法获取了该ArrayList的迭代器对象,并使用while循环遍历迭代器。

在循环中,首先使用hasNext()方法检查是否还有下一个元素,然后使用next()方法获取下一个元素。如果当前元素的值等于"MYSQL",则会打印出".........."。接着,在if条件中,代码尝试往列表中添加一个新元素"JDBC"。

然而,由于在迭代器遍历过程中对列表进行了结构性修改(添加元素),根据快速失败机制,会抛出ConcurrentModificationException异常。这是因为在这个案例中,通过迭代器遍历列表,而在遍历过程中修改了列表的结构。

解决该异常我们可以使用for循环,实现元素的添加

        List<String> list = new ArrayList<>();
        list.add("JavaSE");
        list.add("MYSQL");
        list.add("JavaWeb");
        list.add("JavaEE");

        for (int i = 0; i < list.size(); i++) {
           if ("MYSQL".equals(list.get(i))){
                list.add("JDBC");
           }
        }
        System.out.println(list);

在循环中,首先通过list.get(i)获取索引为i的元素,然后判断是否等于"MYSQL"。如果相等,则在列表末尾添加一个新元素"JDBC"

还可以使用listIterator来解决

        List<String> list = new ArrayList<>();
        list.add("JavaSE");
        list.add("MYSQL");
        list.add("JavaWeb");
        list.add("JavaEE");
        ListIterator<String> lt = list.listIterator();
        while (lt.hasNext()){
            String str = lt.next();
            if ("MYSQL".equals(str)){
                lt.add("JDBC");
            }
        }
        System.out.println(list);
   

在迭代器的循环中,首先通过lt.next()方法获取下一个元素,然后判断是否等于"MYSQL"。如果相等,则使用lt.add("JDBC")方法在当前元素之前插入一个新元素"JDBC"。

在这种情况下,迭代器的添加操作不会影响迭代的继续进行,并且不会引发ConcurrentModificationException异常。迭代器内部会自动处理这种并发性修改。

最后,打印输出列表的内容。由于使用迭代器进行了元素的插入操作,因此列表中会包含"JDBC"这个新元素。结果会输出修改后的列表内容。

5.LinkedList

LinkedList集合是Java中的一种实现了List接口的链表数据结构。它是由一个个节点组成的,每个节点都包含一个值和指向下一个节点的引用。

与ArrayList不同,LinkedList内部的数据结构是一个双向链表,每个节点既有指向下一个节点的引用,也有指向前一个节点的引用。这使得在LinkedList中插入、删除元素时的操作非常高效,因为只需要修改相邻节点的引用即可,而不需要移动其他元素。

LinkedList集合支持动态的增加或删除元素,因为它不需要连续的内存分配。由于链表的特性,LinkedList对于在列表的开头或结尾插入或删除元素效率较高,但对于通过索引访问元素的效率较低。如果需要频繁地使用索引来访问元素,建议使用ArrayList。

LinkedList还实现了Deque接口,因此它可以被当作双端队列来使用,支持在队列的两端进行插入、删除操作。

总之,LinkedList集合提供了一种灵活的、高效的链表数据结构,适用于需要频繁进行插入、删除操作的场景,但在索引访问方面的性能稍逊于ArrayList。

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class StuShow {
    public static void main(String[] args) {
        LinkedList<Student> stuList = new LinkedList<>();
        stuList.add(new Student("Jack",19));
        stuList.add(new Student("Kite",14));
        stuList.add(new Student("bill",15));
        stuList.add(new Student("lily",18));

        for (int i = 0; i < stuList.size(); i++) {
            System.out.println("姓名"+stuList.get(i).getName()+"年龄"+stuList.get(i).getAge());
        }

        for (Student stu : stuList) {
            System.out.println("姓名"+stu.getName()+"年龄"+stu.getAge());
        }

        ListIterator<Student> it = stuList.listIterator();
        while(it.hasNext()){
            Student stu = it.next();
            System.out.println("姓名"+stu.getName()+"年龄"+stu.getAge());
        }
    }
}

这段代码是一个示例,展示了如何使用LinkedList集合存储和遍历Student对象。

首先,在main方法中创建了一个LinkedList对象stuList,用于存储Student对象。然后,通过stuList.add方法依次添加了4个Student对象到集合中,每个对象包含姓名和年龄信息。

接下来,通过两种方式进行遍历集合中的元素。第一种方式是使用for循环和索引,通过stuList.size()方法获取集合的大小,使用get方法获取指定索引位置的Student对象,然后通过getName和getAge方法获取对象的姓名和年龄,并打印出来。

第二种方式是使用增强for循环,直接遍历stuList中的每个Student对象,并通过getName和getAge方法获取对象的姓名和年龄,并打印出来。

第三种方式通过ListIterator迭代器来遍历集合中的元素。首先,通过stuList.listIterator()方法获取ListIterator对象,然后使用while循环和it.hasNext()方法判断是否有下一个元素,如果有则通过it.next()方法获取下一个Student对象,再通过getName和getAge方法获取对象的姓名和年龄,并打印出来。

这段代码展示了LinkedList集合的常见用法,包括添加、遍历、获取元素等操作。

上一篇:【云原生】Kubernetes-kubeadm升级版本