Java中的 Stream 流03

时间:2023-04-05 08:59:51

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的质数,使用并行流后,将分为两个线程来分别求解,最后再将结果汇总到一块。

Java中的 Stream 流03

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));
}