IntStream 类型包括一个 range 函数,该函数在指定的范围内生成一个整数值流,在本例中,以 1 为增量,从 1 递增到 2048 。parallel 函数自动划分该工作到多个线程中,在各个线程中进行过滤和打印 。(线程数通常与主机系统上的 CPU 数量匹配 。)函数 forEach 参数是一个方法引用,在本例中是对封装在 System.out 中的 println 方法的引用,方法输出类型为 PrintStream 。方法和构造器引用的语法将在稍后讨论 。
由于具有多线程,因此整数值整体上以任意顺序打印,但在给定线程中是按顺序打印的 。例如,如果线程 T1 打印 409 和 411,那么 T1 将按照顺序 409-411 打印,但是其它某个线程可能会预先打印 2045 。parallel 调用后面的线程是并发执行的,因此它们的输出顺序是不确定的 。
map/reduce 模式map/reduce 模式在处理大型数据集方面变得很流行 。一个 map/reduce 宏操作由两个微操作构成 。首先,将数据分散( 映射(mapped))到各个工作程序中,然后将单独的结果收集在一起 —— 也可能收集统计起来成为一个值,即 归约(reduction) 。归约可以采用不同的形式,如以下示例所示 。
下面 Number 类的实例用 EVEN 或 ODD 表示有奇偶校验的整数值:
public class Number { enum Parity { EVEN, ODD } private int value; public Number(int n) { setValue(n); } public void setValue(int value) { this.value = https://www.jinnalai.com/fenxiang/value; } public int getValue() { return this.value; } public Parity getParity() { return ((value & 0x1) == 0) ? Parity.EVEN : Parity.ODD; } public void dump() { System.out.format("Value: %2d (parity: %s)\n", getValue(), (getParity() == Parity.ODD ? "odd" : "even")); }}
下面的代码演示了用 Number 流进行 map/reduce 的情形,从而表明流 API 不仅可以处理 int 和 float 等基本类型,还可以处理程序员自定义的类类型 。
在下面的代码段中,使用了 parallelStream 而不是 stream 函数对随机整数值列表进行流化处理 。与前面介绍的 parallel 函数一样,parallelStream 变体也可以自动执行多线程 。
final int howMany = 200;Random r = new Random();Number[] nums = new Number[howMany];for (int i = 0; i < howMany; i++) nums[i] = new Number(r.nextInt(100));List<Number> listOfNums = Arrays.asList(nums); // 将数组转化为 listInteger sum4All = listOfNums .parallelStream() // 自动执行多线程 .mapToInt(Number::getValue) // 使用方法引用,而不是 lambda .sum(); // 将流值计算出和值System.out.println("The sum of the randomly generated values is: " + sum4All);
高阶的 mapToInt 函数可以接受一个 lambda 作为参数,但在本例中,它接受一个方法引用,即 Number::getValue 。getValue 方法不需要参数,它返回给定的 Number 实例的 int 值 。语法并不复杂:类名 Number 后跟一个双冒号和方法名 。回想一下先前的例子 System.out::println,它在 System 类中的 static 属性 out 后面有一个双冒号 。
方法引用 Number::getValue 可以用下面的 lambda 表达式替换 。参数 n 是流中的 Number 实例中的之一:
mapToInt(n -> n.getValue())
通常,lambda 表达式和方法引用是可互换的:如果像 mapToInt 这样的高阶函数可以采用一种形式作为参数,那么这个函数也可以采用另一种形式 。这两个函数式编程结构具有相同的目的 —— 对作为参数传入的数据执行一些自定义操作 。在两者之间进行选择通常是为了方便 。例如,lambda 可以在没有封装类的情况下编写,而方法则不能 。我的习惯是使用 lambda,除非已经有了适当的封装方法 。
推荐阅读
- c语言退出程序命令exit c语言exit函数用法
- 矩阵所有元素求和的公式 matlab矩阵求和函数
- c语言圆的面积编程 c语言阶乘函数怎么写
- 同位语从句经典例句 求同位语的具体用法和例句分析。
- spend的用法
- 并列连词 并列连词与从属连词的用法区别?
- 《如龙:极》鬼炎用法技巧解析攻略
- 对马岛之魂辅助功能有什么 对马之魂辅助功能用法介绍
- 团战经理骑士怎么用 团战经理骑士用法详解
- 团战经理狙击手好用吗 团战经理狙击手用法介绍