三、并行数据
1.流合并
常用的Stream API 包括filter、map、sorted都统称为聚合操作(把集合中的对象做整体性的计算)。
案例1.:
对1-10的十个正整数求和
import java.util.Arrays;
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
int sum = numbers.stearm()
.reduce((a,b) -> a+b)
.get();
System.out.println(sum);
reduce()方法的作用,是合并了所有的元素,终止计算出一个结果,注意这里是终止的意思,就是流已经到达终点结束了,不能继续流动了。
事实上,forEach()也是流的终点
reduce()方法的返回值是一个比较复杂的对象,需要调用get方法返回最终的整数值。
同理,get()方法的返回值类型,也是系统自动根据流中元素类型推定的。
详解reduce()方法的参数
a参数在第一次执行计算a+b时,指代流的第一个元素,然后充当缓存作用以存放本次计算的结果,此后执行计算语句时,a的值就是上一次计算结果并继续充当缓存存放本次计算结果
b参数第一次执行计算语句时指代流的第二个元素,此后一次指代流的每个元素
a、b两个参数的作用是由位置决定的,变量名是任意的
案例2.:计算学生成绩之和
reduce()方法也可以操作对象
List<Student> students = new ArrayList<>();
students.add(new Student("张三", 92));
students.add(new Student("王五", 60));
... ...
... ...
reduce()提供了另一种参数形式,可以自己new一个对象,充当缓存对象,而不是使用流中的原始对象
Student result = students.stream()
.reduce(new Student("", 0),
(a, b) -> {
a.setMidtermScore(a.getMidtermScore() + b.getMidtermScore());
return a;
}
);
System.out.println(result.getName() + " - " + result.getMidtermScore());
reduce()方法的参数变成了两个
第一个参数,是作为缓存角色的对象
第二个参数,是Lambda表达式,那么a就不再指代流中的第一个元素了,专门指代缓存角色的对象,即方法的第一哥参数对象,b一次指代流的每个元素,包括第一个元素
redece()方法的返回值同样发生了变化
返回作为缓存角色的对象,即第一个参数,不用再调用一次get()方法了
2、流收集
再来学习一种属于终点的流操作:收集
在实际开发中,整体的功能如果比较复杂的话,使用流对集合进行计算后,可能并不想输出和合并,而是把结果元素放在一个新的集合中,待进一步使用。
案例3.:
将一组数字
List<Integer> numbers = Arrays.asList(3, 2, 2, 7, 63, 2, 3, 5);
找到最大的前三个数字放入一个新的集合中,用 - 组合成字符串并打印
import java.util.stream.Collectors;
List<String> numResult = numbers.stream()
.sorted((n1, n2) -> n2 - n1)
.limit(3)
.map(a -> "" + a)
.collect(Collectors.toList());
String string = String.join("-", numResult);
System.out.println("字符串是: " + string);
为了能够把结果转化为字符串,调用了map()方法把流中原来的整数映射为字符串(""+a),所以collect()方法的返回值类型就是List<String>
3.并行流
stream API很像一个管道,数据从管道流入,管道的显著特点是,每个节点是依次进行的,下一个节点必须等待上一个节点执行完毕,这种执行方式叫做串行.
串行工作模式很难优化,因为这种模式无法发挥多核CPU的优势
只有一个队伍,核再多,也只能等待
为了充分发挥多核CPU的优势,可以把串行模式改为并行计算模式
所谓并行,就是利用多线程,充分发挥多核CPU优势
使用并行流的代码很简单,把stream()方法改为parallelStream()方法即可
parallelStream()以并行的方式执行任务,同时也支持流的收集,合并等计算
不适合使用并行计算的场景
流中每个数据元素之间有逻辑依赖关系
这是因为并行计算使用了多线程,每个线程独立输出数字,而线程的输出时机,是由CPU动态决定的,所以无法确定