java8流及reactor(stream+flow响应式流)
一个java 8的stream是由三部分组成的。数据源,零个或一个或多个中间操作,一个或零个终止操作。
中间操作是对数据的加工,注意,中间操作是lazy操作,并不会立马启动,需要等待终止操作才会执行。
终止操作是stream的启动操作,只有加上终止操作,stream才会真正的开始执行。
lambda实现惰性求值
什么是惰性求值(惰性计算)
在编程语言理论中,惰性求值(英语:Lazy Evaluation),又译为惰性计算、懒惰求值,也称为传需求调用(call-by-need),是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。它有两个相关而又有区别的含意,可以表示为“延迟求值”和“最小化求值”,本条目专注前者,后者请参见最小化计算条目。除可以得到性能的提升外,惰性计算的最重要的好处是它可以构造一个无限的数据类型。
惰性求值的相反是及早求值(热情求值),这是在大多数编程语言中随处可见的一种计算方式,例如:
int x = 1; String name = getUserName();
上面的表达式在绑定了变量后就立即求值,得到计算的结果。
Java中的惰性求值
以下Java代码就是惰性求值的范例。这段代码在定义 nameStream 这个流的时候,System.out.println 语句不会被立即执行。
public static void main(String[] args) { // 定义流 Stream<String> nameStream = Stream.of("Zebe", "July", "Yaha").filter(name -> { if (!name.isEmpty()) { System.out.println("过滤流,当前名称:" + name); return true; } return false; }); // 取出流的值,这时候才会调用计算 List<String> names1 = nameStream.collect(Collectors.toList()); // 流只能被使用一次,下面这行代码会报错,提示流已经被操作或者关闭了 List<String> names2 = nameStream.collect(Collectors.toList()); }
在jdk8的stream流编程里面,没有调用最终操作的时候,中间操作的方法都不会执行,这也是惰性求值。
stream流编程
stream编程主要是学习API的使用,但前提是学好lambda,基础好了,看这些方法定义非常简单,要是没有打好基础,你会有很多东西需要记忆。
内部迭代和外部迭代
一般来说,我们之前的编码方法,叫外部迭代,stream的写法叫内部迭代。内部迭代代码更加可读更加优雅,关注点是做什么(外部迭代关注是怎么样做),也很容易让我们养成编程小函数的好习惯!这点在编程习惯里面非常重要!看例子:
package com.dxz.stream; import java.util.stream.IntStream; public class StreamDemo1 { public static void main(String[] args) { int[] nums = { 1, 2, 3 }; // 外部迭代 int sum = 0; for (int i : nums) { sum += i; } System.out.println("结果1为:" + sum); // 使用stream的内部迭代 // map就是中间操作(返回stream的操作) // sum就是终止操作 int sum2 = IntStream.of(nums).map(StreamDemo1::doubleNum).sum(); System.out.println("结果2为:" + sum2); System.out.println("惰性求值就是终止没有调用的情况下,中间操作不会执行,下面的不会打印了"); IntStream.of(nums).map(StreamDemo1::doubleNum); } public static int doubleNum(int i) { System.out.println("执行了乘以2"); return i * 2; } }
结果:
结果1为:6 执行了乘以2 执行了乘以2 执行了乘以2 结果2为:12 惰性求值就是终止没有调用的情况下,中间操作不会执行,下面的不会打印了
操作类型
操作类型概念要理清楚。有几个维度。
首先分为 中间操作 和 最终操作,在最终操作没有调用的情况下,所有的中级操作都不会执行。那么那些是中间操作那些是最终操作呢? 简单来说,返回stream流的就是中间操作,可以继续链式调用下去,不是返回stream的就是最终操作。这点很好理解。
最终操作里面分为短路操作和非短路操作,短路操作就是limit/findxxx/xxxMatch这种,就是找了符合条件的就终止,其他的就是非短路操作。在无限流里面需要调用短路操作,否则像炫迈口香糖一样根本停不下来!
中间操作又分为 有状态操作 和 无状态操作,怎么样区分呢? 一开始很多同学需要死记硬背,其实你主要掌握了状态这个关键字就不需要死记硬背。状态就是和其他数据有关系。我们可以看方法的参数,如果是一个参数的,就是无状态操作,因为只和自己有关,其他的就是有状态操作。如map/filter方法,只有一个参数就是自己,就是无状态操作;而distinct/sorted就是有状态操作,因为去重和排序都需要和其他数据比较,理解了这点,就不需要死记硬背了!
为什么要知道有状态和无状态操作呢?在多个操作的时候,我们需要把无状态操作写在一起,有状态操作放到最后,这样效率会更加高。
运行机制
我们可以通过下面的代码来理解stream的运行机制
package com.dxz.stream; import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; /** * 验证stream运行机制 * * 1. 所有操作是链式调用, 一个元素只迭代一次 * 2. 每一个中间操作返回一个新的流. 流里面有一个属性sourceStage指向同一个 地方,就是Head * 3. Head->nextStage->nextStage->... -> null * 4. 有状态操作会把无状态操作阶段,单独处理 * 5. 并行环境下, 有状态的中间操作不一定能并行操作. * * 6. parallel/ sequetial 这2个操作也是中间操作(也是返回stream) * 但是他们不创建流, 他们只修改 Head的并行标志 * */ public class RunStream { public static void main(String[] args) { Random random = new Random(); // 随机产生数据 Stream<Integer> stream = Stream.generate(() -> random.nextInt()) // 产生500个 ( 无限流需要短路操作. ) .limit(50) // 第1个无状态操作 .peek(s -> print("peek相当于debug操作: " + s)) // 第2个无状态操作,大于1000000的值留下 .filter(s -> { print("filter: " + s); return s > 1000000; }) // 有状态操作 .sorted((i1, i2) -> { print("排序: " + i1 + ", " + i2); return i1.compareTo(i2); }) // 又一个无状态操作 .peek(s -> { print("peek相当于debug操作2: " + s); }).parallel(); // 终止操作 long count = stream.count(); System.out.println("end=" + count); } /** * 打印日志并sleep 5 毫秒 * * @param s */ public static void print(String s) { // System.out.println(s); // 带线程名(测试并行情况) System.out.println(Thread.currentThread().getName() + " > " + s); /*try { TimeUnit.MILLISECONDS.sleep(5); } catch (InterruptedException e) { }*/ } }
结果:
ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 467408314 ForkJoinPool.commonPool-worker-1 > filter: 467408314 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -694002895 ForkJoinPool.commonPool-worker-1 > filter: -694002895 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1018018271 ForkJoinPool.commonPool-worker-1 > filter: 1018018271 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -2055711792 ForkJoinPool.commonPool-worker-1 > filter: -2055711792 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 362753392 ForkJoinPool.commonPool-worker-1 > filter: 362753392 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1420256006 ForkJoinPool.commonPool-worker-1 > filter: 1420256006 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1759751716 ForkJoinPool.commonPool-worker-1 > filter: 1759751716 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1451030142 ForkJoinPool.commonPool-worker-1 > filter: -1451030142 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1091423344 ForkJoinPool.commonPool-worker-1 > filter: -1091423344 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1377817193 ForkJoinPool.commonPool-worker-1 > filter: 1377817193 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1159545806 ForkJoinPool.commonPool-worker-1 > filter: -1159545806 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -173182413 ForkJoinPool.commonPool-worker-1 > filter: -173182413 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 600209961 ForkJoinPool.commonPool-worker-1 > filter: 600209961 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1200504990 ForkJoinPool.commonPool-worker-1 > filter: 1200504990 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 260857935 ForkJoinPool.commonPool-worker-1 > filter: 260857935 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -2078810651 ForkJoinPool.commonPool-worker-1 > filter: -2078810651 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 402189452 ForkJoinPool.commonPool-worker-1 > filter: 402189452 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -946047183 ForkJoinPool.commonPool-worker-1 > filter: -946047183 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1516256407 ForkJoinPool.commonPool-worker-1 > filter: -1516256407 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -161522096 ForkJoinPool.commonPool-worker-1 > filter: -161522096 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 346222819 ForkJoinPool.commonPool-worker-1 > filter: 346222819 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1492195164 ForkJoinPool.commonPool-worker-1 > filter: -1492195164 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -823860607 ForkJoinPool.commonPool-worker-1 > filter: -823860607 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1400321699 ForkJoinPool.commonPool-worker-1 > filter: -1400321699 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -594055512 ForkJoinPool.commonPool-worker-1 > filter: -594055512 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -968008982 ForkJoinPool.commonPool-worker-1 > filter: -968008982 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -538739410 ForkJoinPool.commonPool-worker-1 > filter: -538739410 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1403417684 ForkJoinPool.commonPool-worker-1 > filter: -1403417684 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -938859220 ForkJoinPool.commonPool-worker-1 > filter: -938859220 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1962390769 ForkJoinPool.commonPool-worker-1 > filter: -1962390769 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1952141841 ForkJoinPool.commonPool-worker-1 > filter: 1952141841 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 68659719 ForkJoinPool.commonPool-worker-1 > filter: 68659719 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -397822084 ForkJoinPool.commonPool-worker-1 > filter: -397822084 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1047484685 ForkJoinPool.commonPool-worker-1 > filter: 1047484685 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 2051123152 ForkJoinPool.commonPool-worker-1 > filter: 2051123152 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1789203084 ForkJoinPool.commonPool-worker-1 > filter: 1789203084 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1447008850 ForkJoinPool.commonPool-worker-1 > filter: -1447008850 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1982526816 ForkJoinPool.commonPool-worker-1 > filter: 1982526816 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 432837685 ForkJoinPool.commonPool-worker-1 > filter: 432837685 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 2139658303 ForkJoinPool.commonPool-worker-1 > filter: 2139658303 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1386330515 ForkJoinPool.commonPool-worker-1 > filter: 1386330515 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 5070967 ForkJoinPool.commonPool-worker-1 > filter: 5070967 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -2131175714 ForkJoinPool.commonPool-worker-1 > filter: -2131175714 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 390402009 ForkJoinPool.commonPool-worker-1 > filter: 390402009 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1096668893 ForkJoinPool.commonPool-worker-1 > filter: -1096668893 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -929907211 ForkJoinPool.commonPool-worker-1 > filter: -929907211 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1859217343 ForkJoinPool.commonPool-worker-1 > filter: 1859217343 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -1526881589 ForkJoinPool.commonPool-worker-1 > filter: -1526881589 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: 1122349191 ForkJoinPool.commonPool-worker-1 > filter: 1122349191 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作: -882024070 ForkJoinPool.commonPool-worker-1 > filter: -882024070 main > 排序: 1018018271, 467408314 main > 排序: 362753392, 1018018271 main > 排序: 362753392, 1018018271 main > 排序: 362753392, 467408314 main > 排序: 1420256006, 467408314 main > 排序: 1420256006, 1018018271 main > 排序: 1759751716, 1018018271 main > 排序: 1759751716, 1420256006 main > 排序: 1377817193, 1018018271 main > 排序: 1377817193, 1759751716 main > 排序: 1377817193, 1420256006 main > 排序: 600209961, 1377817193 main > 排序: 600209961, 467408314 main > 排序: 600209961, 1018018271 main > 排序: 1200504990, 1018018271 main > 排序: 1200504990, 1420256006 main > 排序: 1200504990, 1377817193 main > 排序: 260857935, 1200504990 main > 排序: 260857935, 600209961 main > 排序: 260857935, 467408314 main > 排序: 260857935, 362753392 main > 排序: 402189452, 1018018271 main > 排序: 402189452, 467408314 main > 排序: 402189452, 362753392 main > 排序: 346222819, 1018018271 main > 排序: 346222819, 402189452 main > 排序: 346222819, 362753392 main > 排序: 346222819, 260857935 main > 排序: 1952141841, 600209961 main > 排序: 1952141841, 1377817193 main > 排序: 1952141841, 1759751716 main > 排序: 68659719, 1018018271 main > 排序: 68659719, 402189452 main > 排序: 68659719, 346222819 main > 排序: 68659719, 260857935 main > 排序: 1047484685, 600209961 main > 排序: 1047484685, 1420256006 main > 排序: 1047484685, 1200504990 main > 排序: 1047484685, 1018018271 main > 排序: 2051123152, 1018018271 main > 排序: 2051123152, 1420256006 main > 排序: 2051123152, 1952141841 main > 排序: 1789203084, 1018018271 main > 排序: 1789203084, 1420256006 main > 排序: 1789203084, 1952141841 main > 排序: 1789203084, 1759751716 main > 排序: 1982526816, 1047484685 main > 排序: 1982526816, 1759751716 main > 排序: 1982526816, 1952141841 main > 排序: 1982526816, 2051123152 main > 排序: 432837685, 1047484685 main > 排序: 432837685, 402189452 main > 排序: 432837685, 600209961 main > 排序: 432837685, 467408314 main > 排序: 2139658303, 1047484685 main > 排序: 2139658303, 1789203084 main > 排序: 2139658303, 1982526816 main > 排序: 2139658303, 2051123152 main > 排序: 1386330515, 1047484685 main > 排序: 1386330515, 1789203084 main > 排序: 1386330515, 1420256006 main > 排序: 1386330515, 1377817193 main > 排序: 5070967, 1200504990 main > 排序: 5070967, 432837685 main > 排序: 5070967, 346222819 main > 排序: 5070967, 260857935 main > 排序: 5070967, 68659719 main > 排序: 390402009, 1047484685 main > 排序: 390402009, 402189452 main > 排序: 390402009, 260857935 main > 排序: 390402009, 362753392 main > 排序: 1859217343, 1047484685 main > 排序: 1859217343, 1789203084 main > 排序: 1859217343, 2051123152 main > 排序: 1859217343, 1982526816 main > 排序: 1859217343, 1952141841 main > 排序: 1122349191, 1047484685 main > 排序: 1122349191, 1789203084 main > 排序: 1122349191, 1386330515 main > 排序: 1122349191, 1377817193 main > 排序: 1122349191, 1200504990 main > peek相当于debug操作2: 1386330515 ForkJoinPool.commonPool-worker-3 > peek相当于debug操作2: 1200504990 ForkJoinPool.commonPool-worker-3 > peek相当于debug操作2: 1377817193 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作2: 1982526816 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作2: 2051123152 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作2: 2139658303 ForkJoinPool.commonPool-worker-3 > peek相当于debug操作2: 1122349191 ForkJoinPool.commonPool-worker-3 > peek相当于debug操作2: 1789203084 ForkJoinPool.commonPool-worker-2 > peek相当于debug操作2: 432837685 ForkJoinPool.commonPool-worker-2 > peek相当于debug操作2: 467408314 ForkJoinPool.commonPool-worker-2 > peek相当于debug操作2: 402189452 main > peek相当于debug操作2: 1420256006 main > peek相当于debug操作2: 1759751716 ForkJoinPool.commonPool-worker-2 > peek相当于debug操作2: 1018018271 ForkJoinPool.commonPool-worker-2 > peek相当于debug操作2: 1047484685 ForkJoinPool.commonPool-worker-3 > peek相当于debug操作2: 346222819 ForkJoinPool.commonPool-worker-3 > peek相当于debug操作2: 362753392 ForkJoinPool.commonPool-worker-3 > peek相当于debug操作2: 390402009 ForkJoinPool.commonPool-worker-3 > peek相当于debug操作2: 5070967 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作2: 1859217343 ForkJoinPool.commonPool-worker-1 > peek相当于debug操作2: 1952141841 ForkJoinPool.commonPool-worker-2 > peek相当于debug操作2: 68659719 ForkJoinPool.commonPool-worker-2 > peek相当于debug操作2: 260857935 main > peek相当于debug操作2: 600209961 end=24
大家自己测试一下代码,能发现stream的调用方法,就像现实中的流水线一样,一个元素只会迭代一次,但如果中间有无状态操作,前后的操作会单独处理(元素就会被多次迭代)。
jdk9的响应式流
就是reactive stream,也就是flow。其实和jdk8的stream没有一点关系。说白了就一个发布-订阅模式,一共只有4个接口,3个对象,非常简单清晰。写一个入门例子就可以掌握。
package jdk9;
import java.util.concurrent.Flow.Processor;
import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;
import java.util.concurrent.SubmissionPublisher;
/**
* 带 process 的 flow demo
*/
/**
* Processor, 需要继承SubmissionPublisher并实现Processor接口
*
* 输入源数据 integer, 过滤掉小于0的, 然后转换成字符串发布出去
*/
class MyProcessor extends SubmissionPublisher<String>
implements Processor<Integer, String> {
private Subscription subscription;
@Override
public void onSubscribe(Subscription subscription) {
// 保存订阅关系, 需要用它来给发布者响应
this.subscription = subscription;
// 请求一个数据
this.subscription.request(1);
}
@Override
public void onNext(Integer item) {
// 接受到一个数据, 处理
System.out.println("处理器接受到数据: " + item);
// 过滤掉小于0的, 然后发布出去
if (item > 0) {
this.submit("转换后的数据:" + item);
}
// 处理完调用request再请求一个数据
this.subscription.request(1);
// 或者 已经达到了目标, 调用cancel告诉发布者不再接受数据了
// this.subscription.cancel();
}
@Override
public void onError(Throwable throwable) {
// 出现了异常(例如处理数据的时候产生了异常)
throwable.printStackTrace();
// 我们可以告诉发布者, 后面不接受数据了
this.subscription.cancel();
}
@Override
public void onComplete() {
// 全部数据处理完了(发布者关闭了)
System.out.println("处理器处理完了!");
// 关闭发布者
this.close();
}
}