Stream流

本文深入介绍了Java Stream API,包括创建Stream、中间操作如filter、map、flatMap及排序操作sorted,以及终止操作如查找与匹配、归约和收集器的使用。通过实例展示了如何利用Stream API处理集合数据,实现高效的数据操作。
摘要由CSDN通过智能技术生成

Stream流

什么是Stream?
  • 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”
  1. Stream自己不会存储元素(流是基于数据源的对象,它本身不存储数据元素,而是通过管道将数据源的元素传递给操作。)

  2. Stream不会改变源对象。相反,他们会返回一个持有结果的Stream。

  3. 3.Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

流的三大操作

1.创建Stream流

2.通过Stream流对象执行中间操作

3.终端操作会从流的流水线生成结果

1.创建Stream

最常用的直接是集合创建流

/**
 * 创建流
 */
@Test
public void testCreateStream() {
    /*
      集合流
       - Collection.stream() 串行流
       - Collection.parallelStream() 并行流
     */
    Stream<Student> stream = studentList.stream();
    Stream<Student> parallelStream = studentList.parallelStream();

    // 从数组创建
    IntStream stream3 = Arrays.stream(new int[]{2, 3, 5});

    //Stream 静态方法
    //Stream.of(...)
    Stream<Integer> stream4 = Stream.of(1, 2, 3);
}
2.中间操作
  • 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
/**
 * 中间操作
 */
@Test
public void testStreamFeatures() {
   //创建流
    Stream<Student> stream = studentList.stream();
    //过滤年龄小于15的
    Stream<Student> ageStream = stream.filter(stu -> stu.getAge() > 15);
    //使用map得到学生姓名,并打印学生信息
    Stream<String> nameStream = ageStream.map(stu -> {
        System.out.println(stu);
        return stu.getName();
    });
    //执行终止操作
    List<String> stuNameList = nameStream.collect(Collectors.toList());
}

常用的中间操作

方法描述
filter(Predicate predicate)接收一个函数作为参数,根据提供的筛选条件predicate进行过滤
map(Function f)接收一个函数作为参数,该函数会作用到每个元素上,映射成新的元素
flatMap(Function f)接收一个函数作为参数,将流中的每个值都转换成另外一个流,然后所有流连接为一个流
sorted()按照自然顺序进行排序,返回一个新流
sorted(Comparator comp)自定义排序顺序,返回一个新流
skip(long n)将前n个元素进行丢弃,返回一个新流
limit(long maxSize)截取到maSize个数的元素值,返回一个新流
  • map操作

    将R类型的参数,转换为T类型(R与T可以一样),最终转换返回一个新的流。

/**
   * 中间操作 map
   */
  @Test
  public void mapTest() {
      Stream<Student> studentStream = studentList
          .stream();
      //提取学生的姓名  将Student类型转换String类型
      Stream<String> stringStream = studentList
          .stream()
          .map(Student::getName);
      //打印输出
      stringStream.forEach(System.out::println);
  }
  • flatMap 操作

    ​ 将R类型的参数转换为T类型,如果Stream流中的元素是被Stream流所包裹,会将这个元素取出来,重新构成一个新的Stream流

@Test
 public void testFlatMap() {
     //创建一个字符串集合
     List<String> list = Arrays.asList("AB", "CD", "EFG");
     Stream<Character> stream1= list
         .stream()
         .flatMap(this::stringToChar);
     //打印
     System.out.println("入参是String,出参是Stream<Character>:");
     stream1.forEach(System.out::println);
 }
  • filter过滤操作

    ​ filter方法就是基于我们传入的Predicate ,进行过滤数据,过滤后会产生一个新的Stream,不会对源数据产生影响

 @Test
 public void  testFilter(){
     //打印过滤前的学生集合长度
     System.out.println("过滤前学生长度:"+studentList.size());
 
     //过滤年龄小于16岁的学生
     List<Student> filterList = studentList
         .stream()
         .filter(stu -> stu.getAge() > 15)
         .collect(Collectors.toList());
     //打印过滤后的学生集合长度
     System.out.println("过滤前学生长度:"+filterList.size());
     System.out.println("过滤后,源数据源的长度:"+studentList.size());
 }
  • sorted排序操作
  @Test
  public void sortedTest() {
      //学生按照年龄从小到大的排序
      System.out.println("按照年龄从小到大排序:");
      studentList
              .stream()
              .sorted(Comparator.comparing(Student::getAge))
              .forEach(System.out::println);
      //学生按照年龄从大到小的排序
      System.out.println("按照年龄从大到小排序:");
      studentList
              .stream()
              .sorted((stu1,stu2)->stu2.getAge().compareTo(stu1.getAge()))
              .forEach(System.out::println);
  }
  • skip 操作

    skip用于跳过前n个元素,从第n+1个开始获取值

 @Test
 public void skipTest() {
     List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
     list
         .stream()
         .skip(3)
         .forEach(System.out::println);
 }
  • limit 操作

    截取第一个到第n个元素,n+1个元素及其以后的元素都抛弃

 @Test
 public void limitTest() {
     List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
     list
         .stream()
         .limit(3)
         .forEach(System.out::println);
 }
3.终止操作

​ 终止在从流的流水线中(中间操作)生成最终的结果,其结果可以是任何不是流的值,且执行过终止操作的流是不可再使用的

  • 查找与匹配
方法简述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate )检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素总数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c)stream API 使用内部迭代(默认做了外部迭代)
@Test
public void testTermination() {
        //allMatch 检查是否匹配所有元素
        boolean allMatch = studentList
        .stream()
        .allMatch(e -> e.getName().equals("张三"));
        System.out.println("allMatch:" + allMatch);
 
        boolean anyMatch = studentList
        .stream()
        .anyMatch(e -> e.getName().equals("李四"));
        System.out.println("anyMatch:" + anyMatch);

        //noneMatch 检查是否没有匹配元素
        boolean noneMatch = studentList
        .stream()
        .noneMatch(e -> e.getName().equals("java"));
        System.out.println("noneMatch:" + noneMatch);
 
        //findFirst 返回第一个元素
        Optional<Student> findAny = studentList
        .stream()
        .findAny();
        System.out.println("findAny:" + findAny);
 
        //findAny 返回流数据中的任意元素
        Optional<Student> findFirst = studentList
        .stream()
        .findFirst();
        System.out.println("findFirst:" + findFirst);
 
        //count 返回流中总个数
        long count = studentList
        .stream()
        .count();
        System.out.println("count:" + count);
 
        //max 返回流中最大的一个值
        Optional<Student> max = studentList
        .stream()
        .max(Comparator.comparing(Student::getAge));
        System.out.println("max:" + max);
 
        //min 返回流中最小值
        Optional<Student> min = studentList.stream().min(Comparator.comparing(Student::getAge));
        System.out.println("min:" + max);
        }
  • 归约
方法简述
reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回 T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回 Optional

方法1返回的是一个对象T,而方法二返回的是Optional,原因是方法1给了一个初始值iden

@Test
public void test3() {

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
    Integer reduce = list.stream()
            .reduce(45, Integer::sum);

    Optional<Integer> reduce1 = list
                                    .stream()
                                    .reduce(Integer::sum);
}
  • 收集器
方法简述
collect将流转换为其他形式。接收一个Collection接口的实现,用于Stream中元素做汇总的方法

collect常与Collectors进行搭配使用,Collectors中提供了大量的方法可以使用,详见下面表(只是常用的):

方法简述
Collector<T, ?, List> toList它将输入元素 List到一个新的 List 。
Collector<T, ?, Set> toSet将输入元素 Set到一个新的 Set 。
Collector<T, ?, Map<K,U>> toMap它将元素累加到一个 Map ,其键和值是将所提供的映射函数应用于输入元素的结果。
Collector<T, ?, C> toCollection按照遇到的顺序将输入元素累加到一个新的 Collection中
Collector<CharSequence, ?, String> joining返回一个 Collector ,将输入元素连接到一个 String ,按照顺序。
groupingBy返回Collector “由基团”上的类型的输入元件操作实现T ,根据分类功能分组元素,并且在返回的结果Map 。
  • toList
@Test
public void  toListTest(){
    //跳过2个学生,收集一个新的学生集合
    List<Student> students = studentList
                                    .stream()
                                    .skip(2)
                                    .collect(Collectors.toList());
    //打印学生信息
    students.stream().forEach(System.out::println);
}
  • toSet
@Test
public void toSetTest() {
    //收集学生的年龄 转换为set
    Set<Integer> ageSet = studentList
        .stream()
        .map(Student::getAge)
        .collect(Collectors.toSet());
    //打印年龄
    ageSet.forEach(System.out::println);
}
  • tomap (F标识Function,BO标识BinaryOperator)
    • Collector toMap(F keyMapper,F valueMapper)

      分别传入keyMapper、valueMapper的函数式方法,将执行后的结果放入Map中

     @Test
     public void toMapTest() {
         //按照姓名转map
         Map<String, Integer> nameMap = studentList
                 .stream()
                 .collect(
                         Collectors.toMap(Student::getName, Student::getAge)
                 );
         for (Map.Entry<String, Integer> map : nameMap.entrySet()) {
             System.out.println(map.getKey()+","+map.getValue());
         }
     }
    
    • Collector toMap(F keyMapper,F valueMapper, BO mergeFunction)

      ​ 分别传入keyMapper、valueMapper的函数式方法,将执行后的结果放入Map中,其中如果出现key值重复,则使用mergeFunction进行处理

     @Test
     public void toMapTest() {
       //使用学生的年龄作为key值,key重复则保留第一个
         Map<Integer, String> ageMap = studentList
               .stream()
                 .collect(
                       Collectors.toMap(Student::getAge, Student::getName, (v1, v2) -> v1)
                 );
         //打印map值
         for (Map.Entry<Integer, String> map : ageMap.entrySet()) {
             System.out.println(map.getKey()+","+map.getValue());
         }
     }
    
    • Collector toMap(F keyMapper, F valueMapper,BO mergeFunction,Supplier mapSupplier)

      这个方法相比于上面方法多了一个mapSupplier,它可以用于选择哪个Map

     @Test
     public void toMapTest() {
         LinkedHashMap<Integer, String> linkedHashMap = studentList
                 .stream()
                 .collect(
                         Collectors.toMap(Student::getAge, Student::getName, (v1, v2) -> v2, LinkedHashMap::new)
                 );
         TreeMap<Integer, String> treeMap = studentList
                 .stream()
                 .collect(
                       Collectors.toMap(Student::getAge, Student::getName, (v1, v2) -> v2, TreeMap::new)
                 );
     }
    
    • join操作

      joining(CharSequence delimiter),将delimiter加入到流中的每个元素中间,拼接成一个字符串进行返回

     @Test
     public void joinTest(){
         String str = studentList
                 .stream()
                 .map(Student::getName)
             	//将 、 加入到每个元素中间
                 .collect(Collectors.joining("、"));
         System.out.println(str);
     }
     
    
  • groupingBy

    根据某个属性值,对流进行分组,它有3个不同的方法:

    • groupingByConcurrent(Function)

      基于传入的function执行得到相应的key,基于这个key值进行分组

    • groupingBy(Function, Collector)

      基于传入的function执行得到相应的key,基于这个key值进行分组,collector则是基于已经分好组的value,再次做一些操作

    • groupingBy(Function, Supplier, Collector)

      这个相比于上面方法,多了一个Supplier,它表示你分组使用什么样的容器存储,默认是HashMap

    public void groupByTest() {
        //按照学生姓名进行分组
        Map<String, List<Student>> nameMap = studentList
                                                        .stream()
                                                        .collect(
                                                                //groupingByConcurrent(Function)
                                                          Collectors.groupingBy(Student::getName));
    
        //按照学生年龄进行分组.然后再统计每个组的个数
        Map<Integer, Long> ageCountMap = studentList
                                                    .stream()
                                                    .collect(
                                                            // groupingBy(Function, Collector)
                                                            Collectors.groupingBy(Student::getAge, 		                                                                                    Collectors.counting()));
    
        //按照学生年龄进行分组.然后再统计每个组的个数 使用TreeMap进行存储
        TreeMap<Integer, Long> ageCountTreeMap = studentList
                .stream()
                .collect(
                        // groupingBy(Function, Collector)
                        Collectors.groupingBy(Student::getAge, TreeMap::new, Collectors.counting())
                );
        for (Map.Entry<Integer, Long> integerLongEntry : ageCountMap.entrySet()) {
            System.out.println(integerLongEntry.getKey()+","+integerLongE
                               ntry.getValue());
        }
    
    }
    public void groupByTest() {
        //按照学生姓名进行分组
        Map<String, List<Student>> nameMap = studentList
                                                        .stream()
                                                        .collect(
                                                                //groupingByConcurrent(Function)
                                                                Collectors.groupingBy(Student::getName));
    
        //按照学生年龄进行分组.然后再统计每个组的个数
        Map<Integer, Long> ageCountMap = studentList
                                                    .stream()
                                                    .collect(Collectors.groupingBy(Student::getAge,                                                                                         Collectors.counting()));
    
        //按照学生年龄进行分组.然后再统计每个组的个数 使用TreeMap进行存储
        TreeMap<Integer, Long> ageCountTreeMap = studentList
                .stream()
                .collect(
                        // groupingBy(Function, Collector)
                        Collectors.groupingBy(Student::getAge, TreeMap::new, Collectors.counting())
                );
        for (Map.Entry<Integer, Long> integerLongEntry : ageCountMap.entrySet()) {
            System.out.println(integerLongEntry.getKey()+","+integerLongE
                               ntry.getValue());
        }
    
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值