手把手带你体验Stream流

前言

只有光头才能变强。git

文本已收录至个人GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3ygithub

上一篇讲解到了Lambda表达式的使用《最近学到的Lambda表达式基础知识》,还没看的同窗能够先去阅读一下哈~编程

相信也有很多的同窗想要知道:Lambda表达式在工做中哪一个场景会用得比较多?跟Lambda搭边的,使用Stream流会比较多数组

通常人第一次看Stream流的代码,都会有点看不懂(它的代码看起来好像就不是写Java同样.),但愿这篇文章能带你们入个门并发

1、体验Stream流

你们在自学时,大多数会学过一个程序:算出从数组元素的和,当时咱们是怎么写的?通常来讲是这样的:dom

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum = 0;
    for (int i : nums) {
        sum += i;
    }
    System.out.println("结果为:" + sum);
}

若是咱们使用Stream流的话,能够这样:性能

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum2 = IntStream.of(nums).sum();
    System.out.println("结果为:" + sum2);
}

代码量上能够明显看出,用Stream流的方式会少一些。测试

我理解的Stream流编程就是:某些场景会常常用到操做(求和/去重/过滤....等等),已经封装好API给你了,你本身别写了,调我给你提供的API就行了优化

1.1 支持并发

回到咱们最原始的代码:spa

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum = 0;
    for (int i : nums) {
        sum += i;
    }
    System.out.println("结果为:" + sum);
}

若是咱们想要for循环的内部支持并发的话,显然不太好去写。但使用Stream流的方式,调用一个方法就能够支持并发(parallel):

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum2 = IntStream.of(nums).parallel().sum();
    System.out.println("结果为:" + sum2);
}

优势:调API确定是比本身写的代码量要少。

缺点:不太方便调试

为何要使用Stream流在我看来就是以上两个缘由:

  • 方便并发
  • 代码量少(直接调用API)

2、如何使用Stream流?

Stream继承结构图

使用Stream流分为三步:

  1. 建立Stream流
  2. 经过Stream流对象执行中间操做
  3. 执行最终操做,获得结果

三步走

2.1 建立流

建立流咱们最经常使用的就是从集合中建立出流

/**
 * 返回的都是流对象
 * @param args
 */
public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    // 从集合建立
    Stream<String> stream = list.stream();
    Stream<String> stream1 = list.parallelStream();

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

    // 建立数字流
    IntStream intStream = IntStream.of(1, 2, 3);

    // 使用random建立
    IntStream limit = new Random().ints().limit(10);

}

2.2 执行中间操做

怎么理解中间操做?意思是这样的:在上面咱们已经能建立出Stream了,咱们是对Stream进行操做,对Stream操做返回完返回的仍是Stream,那么咱们称这个操做为中间操做。

中间操做 解释

好比,咱们如今有个字符串my name is 007,代码以下:

String str = "my name is 007";

Stream.of(str.split(" ")).filter(s -> s.length() > 2)
    .map(s -> s.length()).forEach(System.out::println);

分解:

一、从字符串数组建立出流对象:

Stream<String> split = Stream.of(str.split(" "));

二、经过流对象的API执行中间操做(filter),返回的仍是流对象:

Stream<String> filterStream = split.filter(s -> s.length() > 2);

三、经过返回的流对象再执行中间操做(map),返回的仍是流对象:

Stream<Integer> integerStream = filterStream.map(s -> s.length());

由于中间操做返回的都是流对象,因此咱们能够链式调用

注意:Stream上的操做并不会当即执行,只有等到用户真正须要结果的时候才会执行(惰性求值)。

好比说,peek()是一个中间操做,返回的是Stream流对象,只要它不执行最终的操做,这个Stream是不会执行的。

String str = "my name is 007";
Stream.of(str.split(" ")).peek(System.out::println); // 不会有信息打印

2.3 执行最终操做

最终操做返回的再也不是Stream对象,调用了最终操做的方法,Stream才会执行。仍是以上面的例子为例:

String str = "my name is 007";
Stream.of(str.split(" ")).peek(System.out::println).forEach(System.out::println)

此次咱们加入了最终操做,因此此次的Stream流会被执行,因为中间操做和最终操做都是执行打印,因此会看到两次打印:

结果图

至于中间操做和最终操做怎么区分,咱们以返回值来看就好了。中间操做返回的是Stream实例对象,最终操做返回的不是Stream实例对象:

Stream接口的方法

最后

这篇文章主要跟你们一块儿初步认识一下Stream流,至于中间操做、最终操做的API讲解我就不写了(网上的教程也不少)

使用Stream的缘由我认为有两个:

  1. JDK库提供现有的API,代码写起来简洁优化
  2. 方便并发。你们能够记住一个结论:在多核状况下,可使用并行Stream API来发挥多核优点。在单核的状况下,咱们本身写的for性能不比Stream API 差多少

参考资料:

乐于输出干货的Java技术公众号:Java3y。公众号内有200多篇原创技术文章、海量视频资源、精美脑图,关注便可获取!

转发到朋友圈是对我最大的支持!

以为个人文章写得不错,点

相关文章
相关标签/搜索