1 Stream 中的串行流和并行流
- Stream 的串行流
1、所有的 Collection 集合都可以通过 Stream 默认方法获取流: list.stream();
2、Stream 接口的静态方法 of 可以获取数组对应的流: Stream.of("zhangsan", "lisi", "wangwu", "zhaosi")
;
- Stream 的并行流
1、并行流是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
2、获取并行流的两种方式:
使用集合的 parallelStream() 方法,直接转为并行流;
使用 stream() 方法转为串行流后,再用 parallel() 方法转为并行流。
3、在使用并行流处理数据时,对流中的数据处理不能有顺序要求,因为内部会采用多线程的方式来处理数据。
List<Integer> nums = Arrays.asList(1,3,5,7,9);
//方式一,直接将集合转为并行流
Stream<Integer> stream = nums.parallelStream();
//方式二,将集合转为串行流,再转为并行流
Stream<Integer> parallel = nums.stream().parallel();
例如计算1-100的质数,使用并行流后,将分为两个线程来分别求解,最后再将结果汇总到一块。
2 串行流和并行流的比较
对一千万条随机数据进行排序,并统计,查看两类流的计算效率。
@Test
public void testParallel(){
List<UUID> list = Stream.iterate(UUID.randomUUID(), t -> UUID.randomUUID()).limit(10000000).collect(Collectors.toList());
System.out.println("测试串行流");
long start = System.nanoTime();
list.stream().sorted().count();
long finish = System.nanoTime();
System.out.println("串行流消耗的时间为 " + TimeUnit.NANOSECONDS.toMillis(finish - start));
System.out.println("测试并行流");
long start2 = System.nanoTime();
list.parallelStream().sorted().count();
long finish2 = System.nanoTime();
System.out.println("并行流消耗的时间为 " + TimeUnit.NANOSECONDS.toMillis(finish2 - start2));
}
输出结果为:
测试串行流
串行流消耗的时间为 5514
测试并行流
并行流消耗的时间为 1939
可以发现,使用并行流相比串行流,大大缩短了计算耗时。
3 无限流
上述代码中使用了无限流:Stream.iterate()
,这也是一种流的创建方式,因为是无限流,后边需要带上 limit() 方法,以便提取指定数量的数据。有两个参数,第一个是生成序列的初始值,第二个为序列元素的生成方式。
@Test
public void testItarate(){
List<Integer> collect = Stream.iterate(1, x -> x * 2).limit(10).collect(Collectors.toList());
collect.forEach(System.out::println);
}
如上边例子中,序列中第一个元素为1;
计算第二个元素时,先将初始值代入第二个参数即元素生成式中,1 * 2 = 2,所以第二个元素为 2;
第三个元素,将第二个元素的数值代入到生成式,即 2 * 2 = 4,所以第三个元素为 4;
依此类推,取到第10个元素为 2^(10-1)=512。
程序的输出结果:
1
2
4
8
16
32
64
128
256
512
4 collect 操作
Stream 的 collect 可以把最后生成的流重新收集成为一个集合或一个数值。也可以称为收集器,或者规约操作。主要依赖于 java.util.stream.Collectors
类中的静态方法来实现。
4.1 流转为 Set
如将最后的流收集成为 Set 对象,可使用 collect(Collectors.toSet())
方法:
@Test
public void testItarate(){
Set<Integer> collect = Stream.iterate(1, x -> x * 2).limit(10).collect(Collectors.toSet());
collect.forEach(System.out::println);
}
输出的结果就会是无序的了。
4.2 流转为 Map
还可将流收集成为 Map 对象,使用 Collectors.toMap()
方法
@Test
public void testItarate(){
Map<String, String> collect = Stream.iterate(1, x -> x * 2).limit(10).collect(Collectors.toMap(String::valueOf, Integer::toHexString));
collect.forEach((x, y) -> System.out.println(x + ":" + y));
}