跳至主要內容

Java - Stream流

codejava约 1060 字大约 4 分钟

Stream流

Java 8 API添加了一个新的抽象称为 流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API 可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过 中间操作(intermediate operation)的处理,最后由 最终操作(terminal operation)得到前面处理的结果。

20241130004116
20241130004116

我们就可以把一个 Stream 当做流水线处理:

public static void main(String[] args) {
    List<String> list = new ArrayList<>(Arrays.asList("aaaa", "asdasda", "AssdW", "xx", "add", "Xss", "sdawErs"));
    // 过滤 长度不超过 3
    // 过滤 首字母不是大写字母
    // 去除 重复字符串
    // filter(...) 里面条件为 true 的会保留
    // distinct 去重
    list = list.stream()
            .filter(str -> str.length() > 3)
            .filter(str -> str.charAt(0) >= 'A' &&  str.charAt(0) <= 'Z')
            .distinct()
            .collect(Collectors.toList());
    System.out.println(list);
}

类似

public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(3);

    list = list.stream()
            .distinct()   //去重(使用equals判断)
            .sorted((a, b) -> b - a)    //进行倒序排列
            .map(e -> e+1)    //每个元素都要执行+1操作
            .limit(2)    //只放行前两个元素
            .collect(Collectors.toList());

    System.out.println(list);
}

当遇到大量的复杂操作时,我们就可以使用 Stream 来快速编写代码,这样不仅代码量大幅度减少,而且逻辑也更加清晰明了(如果你学习过SQL的话,你会发现它更像一个Sql语句)

注意:不能认为每一步是直接依次执行的!

实际上,stream 会先记录每一步操作,而不是直接开始执行内容,当整个链式调用完成后,才会依次进行,也就是说需要的时候,工厂的机器才会按照预定的流程启动。

接下来,我们用一堆随机数来进行更多流操作的演示:

public static void main(String[] args) {
    Random random = new Random();  //没想到吧,Random支持直接生成随机数的流
    random.ints(-100, 100)
            // 生成-100~100之间的,随机int型数字(本质上是一个IntStream)
            .limit(10)   
            //只获取前10个数字(这是一个无限制的流,如果不加以限制,将会无限进行下去!)
            .filter(i -> i < 0)   
            //只保留小于0的数字
            .sorted()    
            //默认从小到大排序
            .forEach(System.out::println);   
            //依次打印
}

我们可以生成一个统计实例来帮助我们快速进行统计:

public static void main(String[] args) {
    Random random = new Random();  //Random是一个随机数工具类
    IntSummaryStatistics statistics = random
            .ints(0, 100)
            .limit(100)
            .summaryStatistics();    //获取语法统计实例
    System.out.println(statistics.getMax());  //快速获取最大值
    System.out.println(statistics.getCount());  //获取数量
    System.out.println(statistics.getAverage());   //获取平均值
}

普通的List只需要一个方法就可以直接转换到方便好用的IntStream了:

public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    list.stream()
            .mapToInt(i -> i)    //将每一个元素映射为Integer类型(这里因为本来就是Integer)
            .summaryStatistics();
}

我们还可以通过flat来对整个流进行进一步细分:

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("A,B");
    list.add("C,D");
    list.add("E,F");   //我们想让每一个元素通过,进行分割,变成独立的6个元素
    list = list
            .stream()    //生成流
            .flatMap(e -> Arrays.stream(e.split(",")))    //分割字符串并生成新的流
            .collect(Collectors.toList());   //汇成新的List
    System.out.println(list);   //得到结果
}

我们也可以只通过Stream来完成所有数字的和,使用reduce方法:

public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    int sum = list
            .stream()
            .reduce((a, b) -> a + b)   //计算规则为:a是上一次计算的值,b是当前要计算的参数,这里是求和
            .get();    //我们发现得到的是一个Optional类实例,通过get方法返回得到的值
    System.out.println(sum);
}
上次编辑于: