java加强 -Collection集合

集合是一种容器,类似于数组,但集合的大小可变,开发中也非常常用。Collection代表单列集合,每个元素(数据)只包含1个值。Collection集合分为两类,List集合与set集合。

特点

List系列集合:添加的元素有序,可重复,有指引。

即ArrayList、LinkedList:有序、可重复、有索引。

Set系列集合:添加的元素是无序、不重复、无索引。

HashSet:无序、不重复、无索引;

LinkedHashSet 有序、不重复、无索引。

TreeSet:按大小默认升序排序、不重复、无索引。

(Collection,List与Set是接口,ArrayList等集合是它们的实现类)

示例:

java 复制代码
package Collection;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CollectionDemo1 {
    public static void main(String[] args) {
        //目标:搞清楚Collection集合的整体特点
        //1、list家族的集合:有序,可重复,有索引
        List<String> list = new ArrayList<>();
        list.add("java");
        list.add("java");
        list.add("c++");
        list.add("python");
        System.out.println(list);
       for(int i = 0; i < list.size(); i++)
           System.out.println(list.get(i));
        //2、set家族的集合:无序,不可重复,无索引
        Set<String> set = new HashSet<>();
        set.add("java");
        set.add("java");
        set.add("c++");
        set.add("python");
        System.out.println(set);
        //无索引,没有get方法
 
    }
}

Collection集合的通用方法

java 复制代码
package Collection;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

public class CollectionDemo2 {
    public static void main(String[] args) {
        //目标:搞清楚Collection集合的通用功能
        Collection<String> list = new ArrayList<>();
        //添加集合元素
        list.add("java");
        list.add("c++");
        list.add("python");
        System.out.println(list);
        //判断集合元素个数
        System.out.println(list.size());
        //删除集合元素
        list.remove("c++");
        System.out.println(list);
        //判断集合是否为空
        System.out.println(list.isEmpty());
        //清空集合
        list.clear();
        System.out.println(list.isEmpty());
        System.out.println(list);
        list.add("java");
        list.add("c++");
        //判断集合中是否包含某个元素
        System.out.println(list.contains("java"));
        System.out.println(list.contains("c++"));
        System.out.println(list.contains("python"));
        //集合转数组
//        Object[] arr = list.toArray();
//        for (int i = 0; i < arr.length; i++) {
//            System.out.println(arr[i]);
//        }
        String[] arr = list.toArray(String[]::new);
        System.out.println(Arrays.toString(arr));
    }
}

集合的几种遍历方式

通常,我们有三种方法可以遍历集合

一、迭代器遍历

java 复制代码
package Collection;

import java.util.ArrayList;
import java.util.Iterator;

public class CollectionDemo3 {
    public static void main(String[] args) {
        //目标:理解集合的遍历方式
        //方式一:迭代器遍历
        ArrayList<String> names = new ArrayList<>();
        names.add("林青霞");
        names.add("张曼玉");
        names.add("王祖蓝");
        names.add("柳岩");
        names.add("张无忌");
        System.out.println(names);

        //1、得到一个迭代器对象
        Iterator<String> it = names.iterator();
        //it的位置是集合的第一个位置
        //System.out.println(it.next());      //取出当前位置数据,并且移动到下一个位置
        //while循环遍历
        while(it.hasNext()){    //判断当前位置有没有数据
            String name = it.next();
            System.out.println(name);
        }

    }
}

如上述代码,通过java库中Iterator<数据类型>变量名 来获取一个迭代器对象,用变量名.hasNext()来判断当前位置是否有值,没有值则不进入循环。再通过变量名.next获得当前位置数据,并将指针移向下一位数字来进行数据的输出。

二、增强for循环遍历

java 复制代码
package Collection;

import java.util.ArrayList;

public class CollectionDemo4 {
    public static void main(String[] args) {
        //方式二:增强for循环遍历
        ArrayList<String> names = new ArrayList<>();
        names.add("林青霞");
        names.add("张曼玉");
        names.add("王");
        names.add("柳岩");
        names.add("张无忌");
        System.out.println(names);
        //可以遍历集合,也能遍历数组
        for(String name : names){
            System.out.println(name);
        }
    }
}

这是一个通用的方法,可以用于集合也可以用于数组,用name接收集合中的值并一个个将其打出。

三:Lambda方法:forEach遍历

java 复制代码
package Collection;

import java.util.ArrayList;
import java.util.function.Consumer;

public class CollectionDemo5 {
    public static void main(String[] args) {
        //方式三:Lambda
        ArrayList<String> names = new ArrayList<>();
        names.add("林青霞");
        names.add("张曼玉");
        names.add("王");
        names.add("柳岩");
        names.add("张无忌");
        //forEach(Consumer<? super T> action)
        //这是一个接口,所以需要使用Lambda表达式
//        names.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });
        names.forEach(s -> System.out.println(s));
    }
}

通过重写集合中的accept方法进行遍历。

并发修改异常问题与解决

在遍历一个集合并对其中数据进行修改时,若是在循环中直接删掉一个数容易产生并发修改异常问题。例如,一个集合中有李明,李四,张三,王五 。当我们需要删除名字中带李的人时,遍历到李明时指针为0,李明被删除,数组上移一位,李四变为指针0,可此时指针已经移动到1的位置,李四被略过没删除,这就是并发修改异常问题。

示例

java 复制代码
package Collection;

import java.util.ArrayList;
import java.util.Iterator;

public class CollectionDemo6 {
    public static void main(String[] args) {
        //目标:认识并发修改异常问题,搞清楚每种遍历的区别
        ArrayList<String> list = new ArrayList<>();
        list.add("Java入门");
        list.add("黑枸杞");
        list.add("宁夏枸杞");
        list.add("枸杞");
        list.add("特级枸杞");
        list.add("枸杞子");
        list.add("西洋参");
        System.out.println(list);
        //[Java入门, 黑枸杞, 宁夏枸杞, 枸杞, 特级枸杞, 枸杞子, 西洋参]
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            if (s.contains("枸杞"))
            {
                list.remove(s);
            }
            }
        System.out.println(list);   //枸杞没有删完
        //[Java入门, 宁夏枸杞, 特级枸杞, 西洋参]
        //原因是当遍历到了黑枸杞并删除时,此时索引变成了2,但因为黑枸杞被删了,宁夏枸杞的索引变成了1,所以索引为1的元素被跳过了
        System.out.println("========================================================");
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("Java入门");
        list2.add("黑枸杞");
        list2.add("宁夏枸杞");
        list2.add("枸杞");
        list2.add("特级枸杞");
        list2.add("枸杞子");
        list2.add("西洋参");
        System.out.println(list2);
        //解决方案1:删除时索引-1
//        for (int i = 0; i < list2.size(); i++)
//            {
//                String s = list2.get(i);
//                if (s.contains("枸杞"))
//                {
//                    list2.remove(i);
//                    i--;//删除后索引要减一
//                }
//            }
        //方案二:倒着遍历 (支持索引)
        for (int i = list2.size()-1; i >=0 ; i--) {
            String s = list2.get(i);
            if (s.contains("枸杞"))
                list2.remove(s);
        }
        System.out.println(list2);
        System.out.println("========================================================");
        //三种遍历的区别
        ArrayList<String> list3 = new ArrayList<>();
        list3.add("Java入门");
        list3.add("黑枸杞");
        list3.add("宁夏枸杞");
        list3.add("枸杞");
        list3.add("特级枸杞");
        list3.add("枸杞子");
        list3.add("西洋参");
        System.out.println(list3);
        //一、迭代器遍历删除默认也存在并发修改异常问题

        Iterator<String> it = list3.iterator();
        while (it.hasNext())
            {
                String s = it.next();
                if (s.contains("枸杞"))
                    //it.remove(s);
                    it.remove();//用迭代器自己的方法删
            }
            System.out.println(list3);
        System.out.println("========================================================");
        ArrayList<String> list4 = new ArrayList<>();
        list4.add("Java入门");
        list4.add("黑枸杞");
        list4.add("宁夏枸杞");
        list4.add("枸杞");
        list4.add("特级枸杞");
        list4.add("枸杞子");
        list4.add("西洋参");
        System.out.println(list4);
        //二、三:增强for和Lambda(无法解决并发修改异常)
//        for (String s : list4) {
//            if (s.contains("枸杞"))
//                list4.remove(s);
//        }
        //结论:增强for和Lambda只适合做遍历,不适合遍历并修改
//        System.out.println(list4);
        list4.removeIf(s -> s.contains("枸杞"));
        System.out.println(list4);
    }
}

迭代器遍历内有专门解决这个问题的方法,即迭代器.remove(),删掉当前迭代器指向的值并且指针不动。用正常for循环时,可以用每删一个值指针就向前一位解决。还有一种方法就是从后往前遍历,删除后面的数据对前面的数据不造成影响,也可以正常删除。而增强for和Lambda则没有方法解决这个并发修改异常问题。因此,得出结论,增强for与Lambda适合用于遍历,而遍历同时进行修改则需要使用别的遍历方法。

相关推荐
Tiny番茄1 分钟前
No module named ‘xxx’报错原因及解决方式
开发语言·python
纪元A梦10 分钟前
贪心算法应用:顶点覆盖问题详解
java·算法·贪心算法
咩咩觉主16 分钟前
c#数据结构 线性表篇 非常用线性集合总结
开发语言·数据结构·unity·c#·游戏引擎·程序框架
李匠202438 分钟前
C++GO语言微服务和服务发现②
开发语言·c++·golang·服务发现
bing_15842 分钟前
Spring MVC 中Model, ModelMap, ModelAndView 之间有什么关系和区别?
java·spring·mvc
每次的天空1 小时前
Kotlin 内联函数深度解析:从源码到实践优化
android·开发语言·kotlin
268572591 小时前
JVM 监控
java·开发语言·jvm
promise5241 小时前
JVM之jcmd命令详解
java·linux·运维·服务器·jvm·bash·jcmd
曼岛_1 小时前
[Java实战]Spring Boot 静态资源配置(十三)
java·开发语言·spring boot
篱笆院的狗1 小时前
MySQL 中如何进行 SQL 调优?
java·sql·mysql