Java流式编程

概述

Stream API 是 Java 中引入的一种新的数据处理方法。它提供了一种高效且易于使用的方法来处理数据集合。Stream API 支持函数式编程,可以让我们以简洁、优雅的方式进行数据操作,还有使用 Stream 的两大原因:

  1. 在大多数情况下,将对象存储在集合中就是为了处理它们,因此你会发现你把编程 的主要焦点从集合转移到了流上。
  2. 当 Lambda 表达式和方法引用(method references),流(Stream)结合使用的时候会让人感觉自成一体,行云流水的感觉

先展示一段简单的流式编程:

import java.util.Random;

public class Randoms {
    
    public static void main(String[] args) {
        // 随机展示 5 至 20 之间不重复的整数并进行排序
        new Random(47)
                .ints(5, 20)
                .distinct()             // 使流中的整数不重复
                .limit(7)       		// 获取前 7 个元素
                .sorted()               // 排序
                .forEach(System.out::println);
    }
}

输出结果:

6
10
13
16
17
18
19

实际上函数式的编程风格是声明式(Declarative programming)的,它声明了要做什么, 而不是指明(每一步)如何做。

相同的程序,相比声明式风格,命令式(Imperative)编程的形式(指明每一步如何做),代码阅读起来会更难理解:

import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;

public class ImperativeRandoms {

    public static void main(String[] args) {
        Random rand = new Random(47);
        SortedSet<Integer> rints = new TreeSet<>();
        while (rints.size() < 7) {
            int r = rand.nextInt(20);
            if (r < 5) continue;
            rints.add(r);
        }
        System.out.println(rints);
    }
}

输出结果:

[7, 8, 9, 11, 13, 15, 18]

所以使用流式编程的几个理由:

  1. 表达力强,清晰的语义
  2. 内部迭代 internal iteration (看不见迭代过程)更简单的处理并发
  3. 流式懒加载的,只在绝对必要时才计算

Java 8 通过在添加接口中添加 default 关键字,通过默认方法的方式将流式 Stream 方法平滑地嵌入到现有的类中,

流操作的类型有三种:

  1. 创建流:生产流
  2. 修改流元素:中间操作
  3. 消费流元素:终端操作,收集流元素,通常式汇入一个集合

创建流

通过 Stream.of() 很容见的将一组元素转化为流:

import java.util.stream.Stream;

public class StreamOf {

    public static void main(String[] args) {
        // 创建流
        Stream.of(new Bubble(1), new Bubble(2), new Bubble(3))
                .forEach(System.out::println);

        Stream.of("It's ", "a ", "wonderful ", "day ", "for ", "pie!")
                .forEach(System.out::print);

        System.out.println();
        Stream.of(3.14159, 2.718, 1.618)
                .forEach(System.out::println);
    }
}

输出结果:

Bubble 1
Bubble 2
Bubble 3
It's a wonderful day for pie!
3.14159
2.718
1.618

通过 stream() 方法很容易将传统的集合转化为 Stream:

public class CollectionToStream {

    public static void main(String[] args) {
        List<Bubble> bubbles = Arrays.asList(new Bubble(1), new Bubble(2), new Bubble(3));

        System.out.println(bubbles.stream()  // 将集合转换成为流
                .mapToInt(b -> b.i)          // 获取流中所有元素,对元素进行应用操作,并产生新的对象,这里的 mapToInt 中间操作会转换成为包含整型数字的 IntStream
                .sum());                     // 合计

        HashSet<String> w = new HashSet<>(Arrays.asList("It's a wonderful day for pie!".split(" ")));
        w.stream()
                .map(x -> x + " ")
                .forEach(System.out::print);        // stream 遍历并且打印 Set 中的元素
        System.out.println();

        Map<String, Double> m = new HashMap<>();
        m.put("pi", 3.14159);
        m.put("e", 2.718);
        m.put("phi", 1.618);
        m.entrySet().stream()
                .map(e -> e.getKey() + ": " + e.getValue())
                .forEach(System.out::println);      // stream 遍历并且打印 Map 中的元素
    }
}

输出结果:

6
a pie! It's for wonderful day 
phi: 1.618
e: 2.718
pi: 3.14159

随机数流

Java 8 的 Random 类也集成流的方法,很方便的创建随机数流:

import java.util.Random;
import java.util.stream.Stream;

// 生成随机数流
public class RandomGenerators {

    public static <T> void show(Stream<T> stream) {
        stream.limit(4).forEach(System.out::println);
        System.out.println("++++++++++");
    }

    public static void main(String[] args) {
        Random rand = new Random(47);
        show(rand.ints().boxed());
        show(rand.longs().boxed());
        show(rand.doubles().boxed());
        // 控制上限和下限
        show(rand.ints(10, 20).boxed());
        show(rand.longs(50, 100).boxed());
        show(rand.doubles(20, 30).boxed());
        // 控制流大小
        show(rand.ints(2).boxed());
        show(rand.longs(2).boxed());
        show(rand.doubles(2).boxed());
        // 控制流大小和上限和下限
        show(rand.ints(3, 3, 9).boxed());
        show(rand.longs(3, 12, 22).boxed());
        show(rand.doubles(3, 11.5, 12.3).boxed());
    }
}

输出结果:

-1172028779
1717241110
-2014573909
229403722
++++++++++
2955289354441303771
3476817843704654257
-8917117694134521474
4941259272818818752
++++++++++
# ……………………

int 整型范围

Stream API 对基本数据类型生成流提供便捷的方法,例如对一段整型序列求和,展示新旧代码对比

import java.util.stream.IntStream;

public class Ranges {

    public static void main(String[] args) {
        // 传统方法
        int result = 0;
        for (int i = 0; i < 20; i++) {
            result += i;
        }
        System.out.println(result);

        // 使用流
        System.out.println(IntStream.range(0, 20).sum());
    }
}

输出结果:

190
190

generate()

Stream API 还可以结合 Supplier 函数接口来创建流,例如,创建一个随机数序列:

import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamGenerateExample {

    public static void main(String[] args) {
        Random random = new Random();
        Stream<Integer> randomNumbers = Stream.generate(random::nextInt);

        // 生成 10 个随机数放入集合中
        List<Integer> integers = randomNumbers
                .limit(10)
                .collect(Collectors.toList());

        integers.forEach(System.out::println);
    }
}

输出结果:

514000574
1771591868
600289224
-1474939200
-276604430
-876159270
509964750
-497958443
811408347
703285366

iterate()

Stream.iterate 是 Java 8 引入的 Stream API 的一部分,它接受一个种子值(seed)和一个一元函数(unary operator),然后生成一个无限的、顺序的流。流中的每个元素都是通过对前一个元素应用一元函数生成的。与 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值