java 不可变集合的创建和Stream流的使用

文章目录

    • 一、创建不可变的集合
      • 1.1为什么创建不可变的集合
      • [1.2 创建List、Set和Map的不可变集合](#1.2 创建List、Set和Map的不可变集合)
        • [1.2.1 创建List的不可变集合](#1.2.1 创建List的不可变集合)
        • [1.2.2 创建Set 的不可变集合](#1.2.2 创建Set 的不可变集合)
        • [1.2.3 创建Map的不可变集合](#1.2.3 创建Map的不可变集合)
    • [二、使用集合 的Stream 流](#二、使用集合 的Stream 流)
      • [2.1 Stream的使用步骤](#2.1 Stream的使用步骤)
      • [2.2 Stream的方法](#2.2 Stream的方法)
    • [三、如何获取Stream 流对象](#三、如何获取Stream 流对象)
    • [四、练习使用集合的Stream 流](#四、练习使用集合的Stream 流)

一、创建不可变的集合

1.1为什么创建不可变的集合

  • 不可变集合是线程安全的,因为它们的状态在创建后不会改变。多个线程可以安全地共享和读取不可变集合,而无需同步。
  • 不可变集合不允许修改,可以安全地缓存和重用
  • 在多线程环境下使用 Stream 时,确保没有其他线程修改源集合

1.2 创建List、Set和Map的不可变集合

1.2.1 创建List的不可变集合
  • 方式一

    public class Demo09 {
    public static void main(String[] args) {
    // 创建不可变的List集合
    List<String> list = List.of("张飞","关羽","刘备","曹操","孙权","孙尚香","吕布");

          // 增强for 循环 遍历
          for (String s : list){
              System.out.println(s);
          }
    
          // 迭代器 遍历
          Iterator<String> iterator = list.iterator();
          while (iterator.hasNext()){
              System.out.println(iterator.next());
          }
    
          list.set(0,"张三"); // 集合不可修改,会报异常
      }
    

    }

  • 方式二

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list = Arrays.asList("张飞","关羽","刘备","曹操","孙权","孙尚香","吕布");
    List<String> immutableList = Collections.unmodifiableList(list); // 设置不可变

          // 增强for 循环 遍历
          for (String s : immutableList){
              System.out.println(s);
          }
    
          // 迭代器 遍历
          Iterator<String> iterator = immutableList.iterator();
          while (iterator.hasNext()){
              System.out.println(iterator.next());
          }
    
          immutableList.set(0,"张三"); // 集合不可修改会报异常
      }
    

    }

1.2.2 创建Set 的不可变集合
public class Demo09 {
    public static void main(String[] args) {
        // 创建 Set 的不可变集合
        Set<String> set = Set.of("张飞","关羽","刘备","曹操","孙权","孙尚香","吕布");

        // 增强for 循环遍历
        for (String s : set){
            System.out.println(s);
        }

        //  迭代器遍历
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        set.add("诸葛亮"); // 不可变,报异常
    }
}
1.2.3 创建Map的不可变集合
  • 初版,不建议

    public class Demo09 {
    public static void main(String[] args) {
    // 创建 Map的不可变集合 最多十个键值对,一般不用这种方式
    Map<String,Object> map1 = Map.of("姓名","张三","年龄",25,"地址","北京");

          // 创建不可变的Map 集合,元素个数不限
          Map<String,Object> map = new HashMap<>();
          map.put("姓名","李四");
          map.put("年龄",25);
          map.put("地址","北京");
    
          Set<Map.Entry<String,Object>> entrySet = map.entrySet();
          Map.Entry[] arr1 = new Map.Entry[0];
          // 底层会比较 entrySet 和arr1 的长度 ,长度不够会创建新的数组
          Map.Entry[] arrayEntry = entrySet.toArray(arr1); // Entry数组
    
          Map<String,Object> immutableMap  = Map.ofEntries(arrayEntry); // 不可变集合
    
          immutableMap.put("工资",10000); // 不支持修改,报异常
      }
    

    }

  • 使用copyOf ,建议

    public class Demo09 {
    public static void main(String[] args) {
    // 创建 Map的不可变集合 最多十个键值对,一般不用这种方式
    Map<String,Object> map1 = Map.of("姓名","张三","年龄",25,"地址","北京");

          // 创建不可变的Map 集合,元素个数不限
          Map<String,Object> map = new HashMap<>();
          map.put("姓名","李四");
          map.put("年龄",25);
          map.put("地址","北京");
    
    
          Map<String,Object> immutableMap = Map.copyOf(map); // 创建不可变的集合
          // 遍历方式一
          Set<String> ketSet = map.keySet();
          for (String key:ketSet){
              System.out.println(map.get(key));
          }
    
          // 遍历方式二
          Set<Map.Entry<String,Object>> entrySet = map.entrySet();
          for (Map.Entry entry: entrySet ){
              System.out.println(entry.getKey() + "=" + entry.getValue());
          }
          immutableMap.put("工资",10000); // 不可变,报异常
      }
    

    }

二、使用集合 的Stream 流

2.1 Stream的使用步骤

获取到集合的Stream 流,相当于流水线 --> 把数据交给流处理 ,帅选,检查等 --> 流返回一个新的集合,流水线产品

  • 获取Stream 对象
  • 使用中间方法处理数据
  • 使用终结方法处理数据
  • 结合lambda表达式,简化操作
  • 终结方法一旦被调用,stream对象也就不可用了

2.2 Stream的方法

  • 常用处理方法(中间过程),返回Stream对象,链式调用
  • 终结方法,用于遍历,统计、获取新的集合等,一经调用后Stream 对象就不可用了

三、如何获取Stream 流对象

  • 单列集合(List/Set):使用stream方法
  • 双列集合(Map):不能直接获取,需要转换成Set
  • 数组:Arrays的静态方法stream
  • 一堆零散的数据:Stream 接口的静态方法of

四、练习使用集合的Stream 流

  • 案例一:统计集合中姓张的人数

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list = List.of("刘备","关羽","曹操","张飞","李四","张苞");

          long count = list.stream().filter(s->s.startsWith("张"))
                  .count();
          System.out.println("姓张的总人数:" + count);
      }
    

    }

  • 案例二:输出集合中所有姓张的人名

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list = List.of("刘备","关羽","曹操","张飞","李四","张苞");

          list.stream().filter(s->s.startsWith("张"))
                  .forEach(s -> System.out.println(s));
      }
    

    }

  • 案例三:输出前三个人的名字

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list = List.of("刘备","关羽","曹操","张飞","李四","张苞");

          list.stream().limit(3)
                  .forEach(s -> System.out.println(s));
      }
    

    }

  • 案例四:输出第四个人开始后面所有人的名字

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list = List.of("刘备","关羽","曹操","张飞","李四","张苞");

          list.stream().skip(3)
                  .forEach(s -> System.out.println(s));
      }
    

    }

  • 案例五:去除重复的人名

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list = List.of("刘备","刘备","关羽","曹操","张飞","李四","张苞");

          list.stream().distinct()
                  .forEach(s -> System.out.println(s));
      }
    

    }

  • 案例六:合并两个集合

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list1 = List.of("刘备","刘备","关羽","曹操","张飞","李四","张苞");

          List<String> list2 = List.of("王五","刘六");
    
          Stream<String> stringStream =  Stream.concat(list1.stream(),list2.stream());
          stringStream.forEach(s -> System.out.println(s));
    
      }
    

    }

  • 案例七:将集合的结果保存到数组中

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list1 = List.of("刘备","刘备","关羽","曹操","张飞","李四","张苞");

          Object[] objects =  list1.stream()
                              .distinct()
                              .limit(3)
                              .toArray();
          for (Object o : objects){
              System.out.println(o.toString());
          }
      }
    
  • 案例八:将Stream的处理结果放到集合中

    public class Demo09 {
    public static void main(String[] args) {
    List<String> list1 = List.of("刘备", "刘备", "关羽", "曹操", "张飞", "李四", "张苞");

          // 方式一:不指定具体类型的数组
    

    // Object[] objects = list1.stream()
    // .distinct()
    // .limit(3)
    // .toArray();
    // System.out.println(Arrays.toString(objects));

          // 方式二:指定类型的数组
          String arr[] = list1.stream().toArray(new IntFunction<String[]>() {
              @Override
              public String[] apply(int value) {
                  return new String[value];
              }
          });
          System.out.println(Arrays.toString(arr));
      }
    

    }

改成Lamda 表达式

public class Demo09 {
    public static void main(String[] args) {
        List<String> list1 = List.of("刘备", "刘备", "关羽", "曹操", "张飞", "李四", "张苞");

        // 方式一:不指定具体类型的数组
//        Object[] objects = list1.stream()
//                .distinct()
//                .limit(3)
//                .toArray();
//        System.out.println(Arrays.toString(objects));


        // 方式二:指定类型的数组
        String arr[] = list1.stream().toArray(value -> new String[value]);
        System.out.println(Arrays.toString(arr));
    }
}
  • 将数据收集到集合中

    public class Demo09 {
    public static void main(String[] args) {
    ArrayList<String> arrayList = new ArrayList<>();
    Collections.addAll(arrayList,"张三丰-男-99","周芷若-女-25","张无忌-男-21");
    Collections.unmodifiableList(arrayList);// 设置为不可变的集合

          // 需求1:把所有的男性收集起来,放到一个List集合中
    

    // List<String> newList = arrayList.stream().filter(new Predicate<String>() {
    // @Override
    // public boolean test(String s) {
    // return s.contains("男");
    // }
    // }).collect(Collectors.toList());
    // }

      // 需求2:把所有的男性收集起来,放到一个Set集合中
    

    // Set<String> stringSet = arrayList.stream().filter(s -> s.contains("男"))
    // .collect(Collectors.toSet());
    // System.out.println(stringSet);

      /* 需求3:把所有的男性收集起来,放到一个Map集合中,姓名为键,年龄为值
       toMap的两个参数:参数一:表示键的生成规则,参数二表示值的生成规则
       Function<T, R>的两个参数,T 表示流的数据类型,即apply的参数类型;R表示返回的数据类型,即apply的返回类型
       重要:键不能重复
      */
    
      Map<String,Integer> map = arrayList.stream()
              .filter(s -> "男".equals(s.split("-")[1]))
              .collect(Collectors.toMap(new Function<String, String>() { // 键的生成规则
                                            @Override
                                            public String apply(String s) {
                                                return s.split("-")[0];
                                            }
                                        },
                      new Function<String, Integer>() { // 值的生成规则
                          @Override
                          public Integer apply(String s) {
                              return Integer.parseInt(s.split("-")[2]);
                          }
                      }));
          System.out.println(map);
          }
    

    }

相关推荐
蓝田~几秒前
观察者模式和订阅模式
windows·观察者模式
陌小呆^O^5 分钟前
Cmakelist.txt之win-c-udp-client
c语言·开发语言·udp
儿时可乖了14 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol15 分钟前
java基础概念37:正则表达式2-爬虫
java
I_Am_Me_21 分钟前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
重生之我是数学王子31 分钟前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
xmh-sxh-131432 分钟前
jdk各个版本介绍
java
Ai 编码助手33 分钟前
使用php和Xunsearch提升音乐网站的歌曲搜索效果
开发语言·php
学习前端的小z37 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
神仙别闹44 分钟前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#