前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java Stream流

Java Stream流

作者头像
十玖八柒
发布2022-08-01 09:19:22
2.9K1
发布2022-08-01 09:19:22
举报
文章被收录于专栏:ahzoo.cn的博客分享

前言

与IO流的 Input/Output Stream 不同,Stream 流操作是一个单向的数据处理操作,它不负责数据的储存。可以将Stream流看做是对集合操作功能的增强,可以对集合的各种高效、便利的聚合操作( 类似SQL语句一样的操作, 比如filter,map,sorted等)。同时配合Lambda表达式,极大的提升代码的优雅度。 Stream流不同于其他集合框架,它也不是某种数据结构,它并不会存储元素,而是按需计算,这让它使用起来更像一个高级的迭代器。 Stream不会改变数据源,通常情况下会产生一个新的集合或一个值。

一个标准的Stream流流程:

数据源(创建流) -> 数据处理 / 转换(中间操作) -> 结果处理(终端操作)

中间操作会再次返回一个流,所以我们可以链接多个中间操作;终端操作是对流操作的一个结束动作,一般返回 void或者一个非流的结果。 Stream流具有延迟执行特性,也就是说中间操作不会立即执行,只有调用终端操作的时候,流才会开始中间操作(遍历、映射、过滤等)。并且Stream流提供了并行操作方式,在使用并行计算方式时数据会被自动分解成多段然后并行处理,最后将结果汇总,极大提升程序运行效率。

图片
图片

创建流

stream是顺序流,由主线程按顺序对流执行操作; parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,如果对流中的数据处理没有顺序要求就可以使用并行流。(一般不建议使用并行流,不熟悉的话很容易踩坑,使用情况经常是弊大于利) 例如筛选集合中的奇数,两者的处理不同之处:

图片
图片

常见的创建方式: Collection.stream ()从集合获取流。 Collection.parallelStream ()从集合获取并行流。 Arrays.stream (T array) or Stream.of ()从数组获取流。 BufferedReader.lines () 从输入流中获取流。 IntStream.of () 从静态方法中获取流。 Stream.generate ()or Stream.iterate ()自己生成流。

集合

代码语言:javascript
复制

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class MethodTest {
    @Test
    public void createTest() {
        List<String> list = Arrays.asList("77", "123", "999");
        // 创建一个顺序流
        Stream<String> stream = list.stream();
        // 创建一个并行流
        Stream<String> parallelStream = list.parallelStream();
        
        // 顺序流顺序不会改变
        stream.forEach(System.out::println); // 77 123 999
        
        // 并行流顺序可能会改变
        parallelStream.forEach(System.out::println); // 123 999 
    }
}

数组

代码语言:javascript
复制

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.stream.IntStream;

public class MethodTest {
    @Test
    public void createTest() {
        int[] array = {1, 3, 5, 7, 9, 0};
        IntStream stream = Arrays.stream(array);
        stream.forEach(System.out::println); // 1 3 5 7 9 0
    }
}

文件流

代码语言:javascript
复制
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.stream.Stream;

public class MethodTest {
    @Test
    public void createTest() throws FileNotFoundException {
        // 文件流获取 Stream 流
        BufferedReader bufferedReader = new BufferedReader(new FileReader("README.md"));
        Stream<String> linesStream = bufferedReader.lines();
    }
}

静态方法

使用IntStream的静态方法(of())或者使用Stream自带的静态方法(of()、iterate()、generate())创建流

代码语言:javascript
复制

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class MethodTest {
    @Test
    public void createTest() {
        // 从静态方法获取流操作
        IntStream intStream = IntStream.of(1, 3, 5, 7, 9, 0);
        intStream.forEach(System.out::println); // 1 3 5 7 9 0

        // Stream.of本质就是调用了Arrays.stream(),从数组获取流
        Stream<Integer> stream = Stream.of(1, 3, 5, 7, 9, 0);
        stream.forEach(System.out::println); // 1 3 5 7 9 0

        // 创建一个初始值为7,每次加9,循环3次的流
        Stream<Integer> iterateStream = Stream.iterate(7, num -> num + 9).limit(3);
        iterateStream.forEach(System.out::println); // 7 16 25

        // 将数字循环3次创建流
        Stream<List<Integer>> generateStream = Stream.generate(()->Arrays.asList( 7, 9, 0)).limit(3);
        generateStream.forEach(System.out::println); // [7, 9, 0] [7, 9, 0] [7, 9, 0]

    }
}

Stream创建流的对象不能为null,但是对象中的元素可以为null

代码语言:javascript
复制
Stream<Integer> stream = Stream.of(1, 3, 5, 7, 9, null, 0);
stream.forEach(System.out::println); // 1 3 5 7 9 null 0

Stream<Integer> stream2 = Stream.of(null,null);
stream2.forEach(System.out::println); // null null

// 将会报空指针异常
Stream<Integer> nullStream = Stream.of(null); 

终端操作

遍历/匹配(foreach/find/match)

foreach:遍历元素 find:按条件查找元素 match:判断元素是否符合条件 Stream同样支持类似集合的遍历和匹配元素,但是Stream中的元素类型默认为Optional类型

代码语言:javascript
复制

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class MethodTest {
    @Test
    public void streamTest() {
        List<Integer> list = Arrays.asList(1, 3, 5, 7, 9, 0);
        Stream<Integer> stream = list.stream();
        // 遍历
        stream.forEach(System.out::println); // 1 3 5 7 9 0

//        由于这是终端操作,所以stream操作完后会被关闭,因此再次使用时,需要重新创建
        stream = list.stream();

        // 匹配满足条件的第一个元素(此处没写条件,匹配条件在下面的中间操作中会提到)
        Optional<Integer> first = stream.findFirst();
        // 匹配小于5的第一个元素
        // Optional<Integer> first = list.stream().filter(x -> x < 5).findFirst();
        // 匹配满足条件的任意元素(此处没写条件,匹配条件在下面的中间操作中会提到)任意元素
        Optional<Integer> any = list.stream().findAny();
        
        // 是否包含符合特定条件的元素,只要流中有一个元素满足该断言则返回true,否则返回false
        boolean anyMatch = list.stream().anyMatch(x -> x < 7);
        // allMatch:当流中每个元素都符合该断言时才返回true,否则返回false
        boolean allMatch = list.stream().allMatch(x -> x < 7);
        // noneMatch:当流中每个元素都不符合该断言时才返回true,否则返回false
        boolean noneMatch = list.stream().noneMatch(x -> x < 7);

//        获取匹配到的值
        System.out.println(first.get()); // 1
        System.out.println(any.get()); // 1
        
        System.out.println("存在小于7元素:" + anyMatch + ",全部小于7:" + allMatch + ",全部都不小于7:" + noneMatch); // 存在小于7元素:true,全部小于7:false,全部都不小于7:false

    }
}

约束(reduce)

又称归约、缩减,能实现对集合求和、求乘积和求最值等操作。

代码语言:javascript
复制

List<Integer> list = Arrays.asList(5, 7, 9, 1);

// 求和 对象引用
Optional<Integer> sum = list.stream().reduce(Integer::sum);

// 设置初始值为7
Integer sum2 = list.stream().reduce(7, Integer::sum);

// 求乘积 表达式
Optional<Integer> product = list.stream().reduce((m, n) -> m * n);

// 求最大值
Optional<Integer> max = list.stream().reduce((m, n) -> m > n ? m : n);
Integer max2 = list.stream().reduce(11, Integer::max);

System.out.println("求和:" + sum.get() + ",初始值为7:" + sum2); // 求和:22,初始值为7:29
System.out.println("求积:" + product.get()); // 求积:315
System.out.println("最大值:" + max.get() + ",默认值为11:" + max2); // 最大值:9,默认值为11:11

聚合(max/min/count)

没什么特别说明的,凡是涉及数据操作的都能看到这几个单词。求最大最小值时接收的数据类型为Comparator,可以自定义Comparator实现。

代码语言:javascript
复制
List<Integer> list = Arrays.asList(5, 7, 9, 1, 3);
Optional<Integer> max = list.stream().max(Integer::compareTo);
List<String> list2 = Arrays.asList("77", "a", "123", "999", "ahzoo");
Optional<String> min = list2.stream().min(Comparator.comparing(String::length));
long count = list.stream().count();

System.out.println("最大值:"+max.get()+",长度最短的元素:"+min.get()+",元素数量:"+count); // 最大值:9,长度最短的元素:a,元素数量:5

中间操作

筛选与切片(filter/limit/skip/distinct)

filter:按条件匹配筛选 limit(n):获取n个元素 skip(n):跳过n元素,配合limit(n)可实现分页 distinct:通过流中元素的 hashCode() 和 equals() 去除重复元素

代码语言:javascript
复制
        List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);
//        过滤元素大于3的
        list.stream().filter(x -> x > 1).forEach(System.out::println); // 3 5 7 9
//        过滤元素小于5的第一个元素
        Optional<Integer> first = list.stream().filter(x -> x < 5).findFirst();
        System.out.println(first.get()); // 3  按照list列表顺序元素3在元素1的前面

        System.out.println("---------------------");
//        过滤重复元素
        Stream<Integer> distinctStream = list.stream().distinct();
        distinctStream.forEach(System.out::println);  // 3 5 7 9 1
        System.out.println("---------------------");

//        跳过3个元素
        Stream<Integer> skipStream = list.stream().skip(3);
        skipStream.forEach(System.out::println); // 9 1 3 5
        System.out.println("---------------------");

//        只显示3个元素
        Stream<Integer> limitStream = list.stream().limit(3);
        limitStream.forEach(System.out::println); // 3 5 7
        System.out.println("---------------------");

//        实现每页2个元素, 打印第3页
        Stream<Integer> page = list.stream().skip(4).limit(2);
        page.forEach(System.out::println); // 1 3

映射(map)

将一个流的元素按照一定的映射规则映射到另一个流中。 map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

代码语言:javascript
复制

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class MethodTest {
    @Test
    public void streamTest() {
        List<Integer> list = Arrays.asList(1, 3, 5, 7, 9, 0);
//        将列表元素变为偶数
        List<Integer> evenList = list.stream().map(x -> x * 2).collect(Collectors.toList());

//        将列表转为元素大写
        List<String> list2 = Arrays.asList("ouo", "Abc", "ahzoo");
        List<String> upperList = list2.stream().map(String::toUpperCase).collect(Collectors.toList());

        System.out.println(evenList);// [2, 6, 10, 14, 18, 0]
        System.out.println(upperList); // [OUO, ABC, AHZOO]

        // 创建一个新的流
        Stream<List<String>> mergeStream = Stream.of(list2, upperList);
        // 连接合并
        List<String> mergeList = mergeStream.flatMap(Collection::stream).collect(Collectors.toList());
        System.out.println(mergeList); // [ouo, Abc, ahzoo, OUO, ABC, AHZOO]
    }
}

收集(collection)

将Stream流转换为其他类型。 当我们使用Stream流进行操作时,最终获得的结果是Stream类型的数据,但是大多数情况我们并不想要一个Stream类型的数据,collection就很好的帮我们解决了这个问题。

归集

toList():转为列表 toArray():转为数组 toMap()/toSet():转为集合

代码语言:javascript
复制

import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.stream.Collectors;

public class MethodTest {
    @Test
    public void streamTest() {
        List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);

//         转为列表
        List<Integer> toList = list.stream()
                .collect(Collectors.toList());
        System.out.println(toList); // [3, 5, 7, 9, 1, 3, 5]

        //        collectors转换类型的过程就相当于帮我们创建并复制目标类型的数据,
        //        所以上面的Collectors.toList()方法就相当于完成了下面的这些步骤
        List<Integer> toList2 = list.stream()
                .collect(ArrayList::new, ArrayList::add,
                        ArrayList::addAll);
        System.out.println(toList2); // [3, 5, 7, 9, 1, 3, 5]

//        转为数组
        Integer[] toArray = list.stream()
                .toArray(Integer[]::new);
        System.out.println(Arrays.asList(toArray)); // [3, 5, 7, 9, 1, 3, 5]

//        转为集合
        Set<Integer> toSet = list.stream()
                .collect(Collectors.toSet());
        System.out.println(toSet); // [1, 3, 5, 7, 9]
        
    }
}
统计

Collectors提供的用于数据统计的静态方法: 计数:count 平均值:averagingInt、averagingLong、averagingDouble 最值:maxBy、minBy 求和:summingInt、summingLong、summingDouble 统计以上所有:summarizingInt、summarizingLong、summarizingDouble

代码语言:javascript
复制

List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);

Long count = list.stream().collect(Collectors.counting());
Integer sum = list.stream().collect(Collectors.summingInt(i -> i));
Optional<Integer> max = list.stream().collect(Collectors.maxBy(Integer::compare));
Double average = list.stream().collect(Collectors.averagingInt(i -> i));
IntSummaryStatistics all = list.stream().collect(Collectors.summarizingInt(i -> i));


System.out.println("总数:" + count + " | 和:" + sum + " | 最大值:" + max.get() + " | 平均值:" + average); // 总数:7 | 和:33 | 最大值:9 | 平均值:4.714285714285714
System.out.println("统计所有:" + all); // 统计所有:IntSummaryStatistics{count=7, sum=33, min=1, average=4.714286, max=9}
分组

groupingBy:分组聚合功能,和数据库的 Group by 的功能一致 partitioningBy:按条件分组 可进行嵌套分组 示例1: 列表分组

代码语言:javascript
复制
       List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);

//        按x是否大于5分类(使用表达式)
        Map<Boolean, List<Integer>> collect = list.stream().collect(Collectors.groupingBy(x -> x > 5)); 
        System.out.println(collect); // {false=[3, 5, 1, 3, 5], true=[7, 9]}

示例2: 对象分组

代码语言:javascript
复制

import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.stream.Collectors;

public class MethodTest {
    @Test
    public void streamTest() {

        @Data
        @AllArgsConstructor
        class User {
            private int age;
            private String sex;
        }

        ArrayList<User> users = new ArrayList<>();
        users.add(new User(18, "male"));
        users.add(new User(22, "female"));
        users.add(new User(20, "male"));


//        按对象年龄是否大于19分类(使用表达式)
        Map<Boolean, List<User>> ageCollect = users.stream().collect(Collectors.groupingBy(x -> x.getAge() > 19));
        System.out.println(ageCollect); // {false=[User(age=18, sex=male)], true=[User(age=22, sex=female), User(age=20, sex=male)]}


//        按对象性别分类(使用对象引用)
        Map<String, List<User>> sexCollect = users.stream().collect(Collectors.groupingBy(User::getSex));
        System.out.println(sexCollect); // {female=[User(age=22, sex=female)], male=[User(age=18, sex=male), User(age=20, sex=male)]}
    }
}
接合

joining:将stream中的元素用特定的连接符(可为空)拼接成一个字符串。

代码语言:javascript
复制
        List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);

//        拼接为字符串,无连接符
        String toString = list.stream()
                .map(number -> String.valueOf(number))
                .collect(Collectors.joining()).toString();
        System.out.println(toString); // 3579135


//        拼接为字符串,并用逗号分隔
        String toStringbJoin = list.stream()
                .map(number -> String.valueOf(number))
                .collect(Collectors.joining(",")).toString();
        System.out.println(toStringbJoin); // 3,5,7,9,1,3,5
归约

reducing:和stream本身的reduce方法大同小异,可参照上面的reduce的使用方法

代码语言:javascript
复制
      List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);

//        归约list元素的和
        Optional<Integer> collect = list.stream().collect(Collectors.reducing(Integer::sum));
        System.out.println(collect.get()); // 33

排序(sort)

默认是自然排序,也可以实现Comparator自定义排序

代码语言:javascript
复制
List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);
// 自然排序(升序)
list.stream().sorted().forEach(System.out::println); // 1 3 3 5 5 7 9

// 自定义排序(降序)
Stream<Integer> sorted = list.stream().sorted((o1, o2) -> Integer.compare(o2, o1));
sorted.forEach(System.out::println); // 9 7 5 5 3 3 1

Java9更新

Java9主要增加了 4 个新的方法: takeWhile():从头开始筛选,遇到不满足的条件时就结束。 dropWhile():从头开始删除,遇到不满足的条件时就结束。 ofNullable():创建支持全 null 的 Stream. iterate():重载迭代器(之前只有Stream有此方法,此次在IntStream中也增加了此方法)

takeWhile:

代码语言:javascript
复制
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

public class MethodTest {

    @Test
    public void userTest() {
        List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);
        list.stream().takeWhile(x -> x < 7).forEach(System.out::println);//  3 5
    }
}

dropWhile:

代码语言:javascript
复制

List<Integer> list = Arrays.asList(3, 5, 7, 9, 1, 3, 5);
list.stream().dropWhile(x -> x < 7).forEach(System.out::println);// 7 9 1 3 5

ofNullable:

代码语言:javascript
复制
Stream<Object> stream = Stream.ofNullable(null);
stream.forEach(System.out::println);

iterate:

代码语言:javascript
复制
IntStream stream = IntStream.iterate(7, num -> num + 9).limit(3);
stream.forEach(System.out::println); // 7 16 25
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 创建流
    • 集合
      • 数组
        • 文件流
          • 静态方法
          • 终端操作
            • 遍历/匹配(foreach/find/match)
              • 约束(reduce)
                • 聚合(max/min/count)
                • 中间操作
                  • 筛选与切片(filter/limit/skip/distinct)
                    • 映射(map)
                      • 收集(collection)
                        • 归集
                        • 统计
                        • 分组
                        • 接合
                        • 归约
                      • 排序(sort)
                      • Java9更新
                      相关产品与服务
                      GPU 云服务器
                      GPU 云服务器(Cloud GPU Service,GPU)是提供 GPU 算力的弹性计算服务,具有超强的并行计算能力,作为 IaaS 层的尖兵利器,服务于生成式AI,自动驾驶,深度学习训练、科学计算、图形图像处理、视频编解码等场景。腾讯云随时提供触手可得的算力,有效缓解您的计算压力,提升业务效率与竞争力。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档