• 一篇搞懂进阶集合使用技巧


    一篇搞懂Stream流

    不可变集合(Java9特性)

    不可以被修改的集合,一旦创建完毕长度和内容都不能更改

    应用场景

    • 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。
    • 当集合对象被不可信的库调用时,不可变形式是安全的。
    • 不想让别人修改集合中的内容

    书写格式

    在List、Set、Map接口中,都存在静态的of方法,可以获取一个不可变的集合,这个集合不能添加,不能删除,不能修改。

    方法名称说明
    static List of(E…elements)创建一个具有指定元素的List集合对象
    static Set of(E…elements)创建一个具有指定元素的Set集合对象
    static Map of(E…elements)创建一个具有指定元素的Map集合对象

    小案例

    • List
    public class ImmutableDemo1 {
        public static void main(String[] args) {
            /*创建不可变的List集合"张三","李四","王五","赵六"*/
            //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
            List<String> list = List.of("张三","李四","王五","赵六");
    
            System.out.println(list.get(0));
            System.out.println(list.get(1));
            System.out.println(list.get(2));
            System.out.println(list.get(3));
    
            System.out.println("-----------------------");
    
            for (String s : list){
                System.out.println(s);
            }
    
            System.out.println("-----------------------");
    
            Iterator<String> it = list.iterator();
            while(it.hasNext()){
                String s = it.next();
                System.out.println(s);
            }
    
            System.out.println("-----------------------");
    
            for(int i = 0; i < list.size(); i++) {
                String s = list.get(i);
                System.out.println(s);
            }
    
            System.out.println("-----------------------");
    
            //list.remove("李四");
            //list.add("aaa");
            //list.set(0,"aaa");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • Set
    public class ImmutableDemo2 {
        public static void main(String[] args) {
            /*创建不可变的Set集合"张三","李四","王五","赵六"
             细节: 获取不可变的Set集合时,里面的参数要保证唯一性
            */
           
            //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
            Set<String> set = Set.of("张三","李四","王五","赵六");
    
            for (String s : set){
                System.out.println(s);
            }
    
            System.out.println("-----------------------");
    
            Iterator<String> it = set.iterator();
            while(it.hasNext()){
                String s = it.next();
                System.out.println(s);
            }
    
            System.out.println("-----------------------");
    
            //set.remove("李四");
            //set.add("aaa");
            //set.set(0,"aaa");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • Map
    public class ImmutableDemo3 {
        public static void main(String[] args) {
            /*创建不可变的Map集合
             细节: 键是不可重复的,Map里面的of方法参数有上限,最多存放20个
    			因为可变参数只能放在最后,但键和值有两个可变参数,解决方法组合成键值对
            */
            //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
            Map<String,String> map = Map.of("张三","南京","李四","北京","王五","上海","赵六","广州","孙七","深圳","周八","杭州","吴九","宁波","郑十","苏州","刘一","无锡","陈二","嘉兴");
    
            Set<String> keys = map.keySet();
            for (String key : keys){
                String value = map.get(key);
                System.out.println(key + ":" + value);
            }
    
            System.out.println("-----------------------");
    
            Set<Map.Entry<String,String>> entries = map.entrySet();
            for (Map.Entry<String,String> entry : entries){
                String key = entry.getKey();
                String value = entry.getValue();
                System.out.println(key + ":" + value);
            }
    
            System.out.println("-----------------------");
    
            //list.remove("李四");
            //list.add("aaa");
            //list.set(0,"aaa");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    public class ImmutableDemo4 {
        public static void main(String[] args) {
            /*如果我们要传递多个键值对对象,数量大干10个,在Map接口中还有一个方法 */
            HashMap<String,String> hm = new HashMap<>();
            hm.put("张三","南京");
            hm.put("李四","北京");
            hm.put("王五","上海");
            hm.put("赵六","北京");
            hm.put("孙七","深圳");
            hm.put("周八","杭州");
            hm.put("吴九","宁波");
            hm.put("郑十","苏州");
            hm.put("刘一","无锡");
            hm.put("陈二","嘉兴");
            hm.put("aaa","bbb");
    
            //利用上面的数据获取一个不可变集合,获取到所有的键值对对象(Entry对象〉
            Set<Map.Entry<String,String>> entries = hm.entrySet();
            //把entries变成数组
            Map.Entry[] arr = entries.toArray(new Map.Entry[0]);
            //toArray方法在底层会比较集合的长度跟数组的长度两者的大小
            //如果集合的长度〉数组的长度: 数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
            //如果集合的长度〈= 数组的长度: 数据在数组中放的下,此时不会创建新的数组,而是直接用   
            Map map = Map.ofEntries(arr);
    
            //以上代码可替换为下面一行
            //Map map= Map.ofEntries(hm.entryset().toArray(new Map.Entry[0]));
    
            //Java10新特性
            //Map map = Map.copyOf(hm);
    
            //map.put("bbb","ccc");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    Stream流

    引入案例

    优化前

    public class StreamDemo1 {
        public static void main(String[] args) {
    
            /*
            创建集合添加元素。完成以下需求:
            1.把所有以 张 开头的元素存储到新集合中
            2.把 张 开头的,长度为3的元素再存储到新集合中
            3.遍历打印最终结果
            */
    
            ArrayList<String> list1 = new ArrayList<>();
            list1.add("张无忌");
            list1.add("张三峰");
            list1.add("张良");
            list1.add("周芷若");
    
            //1.把所有以 张 开头的元素存储到新集合中
            ArrayList<String> list2 = new ArrayList<>();
            for (String name : list1) {
                if (name.startsWith("张")) {
                    list2.add(name);
                }
            }
    
            System.out.println(list2);
    
            //2.把 张 开头的,长度为3的元素再存储到新集合中
            ArrayList<String> list3 = new ArrayList<>();
            for (String name : list2) {
                if(name.length() == 3){
                    list3.add(name);
                }
            }
    
            System.out.println(list3);
    
            //3.遍历打印最终结果
            for (String name : list3) {
                System.out.println(name);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    优化后

    public class StreamDemo1 {
        public static void main(String[] args) {
    
            /*
            创建集合添加元素。完成以下需求:
            1.把所有以 张 开头的元素存储到新集合中
            2.把 张 开头的,长度为3的元素再存储到新集合中
            3.遍历打印最终结果
            */
    
            ArrayList<String> list1 = new ArrayList<>();
            list1.add("张无忌");
            list1.add("张三峰");
            list1.add("张良");
            list1.add("周芷若");
    
            list1.stream()
                .filter(name -> name.startsWith("张"))
                .filter(name -> name.length() == 3)
                .forEach(System.out::println);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    Stream流的作用

    结果了Lambda表达式,简化集合、数组操作

    Stream流的使用步骤

    1. 先得到一条Stream流(流水线),并把数据放上去
    2. 使用中间方法对流水线上的数据进行操作
    3. 使用终结方法对流水线上的数据进行操作
    获取方式方法名说明
    单列集合default Stream stream()Collection中的默认方法
    双列集合无法直接使用stream流
    数组public static Stream stream(T[] array)Arrays工具类中的静态方法
    一堆零散数据public static Stream of(T… values)Stream接口中的静态方法
    public class StreamDemo2 {
        public static void main(String[] args) {
            /*
             单列集合          default stream stream()                       Collection中的默认方法
             双列集合              无                                           无法直接使用stream流
             数组             public static cT> Stream stream(T[] array)    Arrays 工具类中的静态方法
             一堆零散数据      public static Stream of(T... values)       Stream接口中的静态方法
            */
    
            //单列集合
            ArrayList<String> list = new ArrayList<>();
            Collections.addAll(list, "A", "B", "C", "D", "E", "F", "G");
            list.stream().forEach(System.out::println);
    
            System.out.println("-------------");
    
            //双列集合
            HashMap<String, Integer> map = new HashMap<>();
            map.put("AA", 1);
            map.put("BB", 2);
            map.put("CC", 3);
    
            map.keySet().stream().forEach(System.out::println);
            System.out.println("~~~~~~~~");
            map.values().stream().forEach(System.out::println);
            System.out.println("~~~~~~~~");
            map.entrySet().stream().forEach(System.out::println);
    
            System.out.println("-------------");
    
            //数组
            int[] arr = {1, 2, 3, 4, 5};
            String[] arr2 = {"A", "B", "C", "D", "E"};
    
            Arrays.stream(arr).forEach(System.out::println);
            Arrays.stream(arr2).forEach(System.out::println);
    
            System.out.println("-------------");
    
    
            //一堆零散数据
            Stream.of(1, 2, 3, 4, 5, 6).forEach(System.out::println);
            Stream.of("A", "B", "C", "D", "E", "F", "G").forEach(System.out::println);
    
            //注意:
            // Stream接口中静态方法of的细节
            // 方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
            // 但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream当中。
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    Stream流的中间方法

    名称说明
    Stream filter(Predicate predicate)过滤
    Stream limit(long maxSize)获取前几个元素
    Stream skip(long n)跳过前几个元素
    Stream distinct()元素去重,依赖(hashCode和equals方法)
    static Stream concat(Stream a, Stream b)合并a和b两个流为一个流
    Stream map(Function mapper)转换流中的数据类型
    • 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
    • 修改Stream流中的数据,不会影响原来集合或者数组中的数据
    public class StreamDemo3 {
        public static void main(String[] args) {
            /*
           filter   过滤
           limit    获取前几个元素
           skip     跳过前几个元素
           distinct 元素去重,依赖(hashcode和equals方法)
           concat   合并a和b两个流为一个流
            map      转换流中的数据类型
            */
    
            ArrayList<String> list = new ArrayList<>();
            Collections.addAll(list, "张无忌","周芷若","赵皈","张强","张三丰","张举山","王二麻子","谢广坤");
    
            // filter 过滤 把 张 开头的名字留下
            list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
    
            System.out.println("-----------------");
    
            // limit    获取前3个元素
            // skip     跳过前2个元素
            list.stream().limit(3).skip(2).forEach(System.out::println);
    
            System.out.println("-----------------");
    
            // distinct 元素去重,依赖(hashcode和equals方法)
            // concat   合并a和b两个流为一个流
            ArrayList<String> list1 = new ArrayList<>();
            Collections.addAll(list1,"张无忌","张无忌","张无忌","张强","张三丰","张举山","张良","王二麻子","谢广坤");
            ArrayList<String> list2 = new ArrayList<>();
            Collections.addAll(list2,"周芷若","赵敏");
    
            list1.stream().distinct().forEach(System.out::println);
    
            Stream.concat(list1.stream(),list2.stream()).forEach(System.out::println);
    
            System.out.println("-----------------");
    
            // map      转换流中的数据类型
            ArrayList<String> list3 = new ArrayList<>();
            Collections.addAll(list3, "张无忌-12", "张强-42", "张三丰-64", "张举山-11", "张良-98", "王二麻子-65", "谢广坤-54");
            //只获取年龄并进行打印
            list3.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(System.out::println);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    Stream流的终结方法

    名称说明
    void forEach(Consumer action)遍历
    long count()统计
    toArray()收集流中的数据,放到数组中
    collect(Collector collector)收集流中的数据,放到集合中
    public class StreamDemo4 {
        public static void main(String[] args) {
            /*
             void forEach(Consumer action)      遍历
             long count()                       统计
             toArray()                          收集流中的数据,放到数组中
             collect(Collector collector)       收集流中的数据,放到集合中(List Set Map)
            */
    
            ArrayList<String> list = new ArrayList<>();
            Collections.addAll(list, "张无忌", "周芷若", "赵皈", "张强", "张三丰", "张举山", "王二麻子", "谢广坤");
    
            //forEach()
            list.stream().forEach(System.out::println);
    
            System.out.println("-------------------");
    
            //count()
            long count = list.stream().count();
            System.out.println(count);
    
            System.out.println("-------------------");
    
            //toArray()
            //toArray方法的参数的作用:负责创建一个指定类型的数组
            //toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
            //toArray方法的返回值:是一个装着流里面所有数据的数组
            Object[] arr = list.stream().toArray();
            String[] arr2 = list.stream().toArray(String[]::new);
            System.out.println(Arrays.toString(arr));
            System.out.println(Arrays.toString(arr2));
    
            System.out.println("-------------------");
    
            //collect()
            ArrayList<String> list2 = new ArrayList<>();
            Collections.addAll(list2, "张无忌-男-12", "张强-男-42", "张三丰-男-64", "张举山-女-11", "张良-女-98", "王二麻子-男-65", "谢广坤-女-54");
            //收集List集合中的男性
            List<String> newList = list2.stream().filter(s -> "男".equals(s.split("-")[1]))
                    .collect(Collectors.toList());
    
             //收集Set集合中的男性
            Set<String> newSet = list2.stream().filter(s -> "男".equals(s.split("-")[1]))
                    .collect(Collectors.toSet());
    
            System.out.println(newList);
            System.out.println(newSet);
    
            System.out.println("~~~~~~~~~~~~");
    
            //收集Map集合中的男性
            //参数一:键的生成规则:Function泛型一:表示流中每一个数据的类型,泛型二:表示Map集合中键的数据类型
            //参数二:值的生成规则:Function泛型一:表示流中每一个数据的类型,泛型二:表示Map集合中值的数据类型
            Map<String, Integer> newMap = list2.stream().filter(s -> "男".equals(s.split("-")[1]))
                    .collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.parseInt(s.split("-")[2])));
            System.out.println(newMap);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
  • 相关阅读:
    Github每日精选(第4期):Swift 下的数据存储CoreStore
    JavaEE在线学习系统的设计与实现
    三维重建之NeRF(pytorch)
    [项目设计] 从零实现的高并发内存池(四)
    Top K 问题解决方案
    Centos 停服倒计时!你的操作系统何去何从?
    H3C交换机环路保护
    【星海随笔】操作系统02326知识点总结
    关于SQL的返回行数top
    有手就行10——Jenkins+SonarQube代码审查
  • 原文地址:https://blog.csdn.net/weixin_65777087/article/details/133465352