关于流的基础知识

Java 8 新特性之 Stream API 基础

流的生成

1.从数组

1
2
3
4
5
//从数组
String[] arr = { "program", "creek", "program", "creek", "java"};
Stream<String>stream = Stream.of(arr);

Stream<String>stream2 = Stream.of("program", "creek", "program", "creek", "java");

2.从集合

1
2
3
4
//从集合里面
List<String>strings = Arrays.asList("abc", "cbc", "bbc", "cbc", "uas","cctv", "cnc");

Stream<String>listStream = strings.stream();

3.使用Stream.generate()

static Stream generate(Supplier s) 返回无限顺序无序流,其中每个元素由提供的供应商生成。 这适合于产生恒定流,随机元素流等。通过实现 Supplier 接口,把 Supplier 实例传递给 Stream.generate() 生成的 Stream,默认是串行(相对 parallel 而言)但无序的(相对 ordered 而言)。由于它是无限的,在管道中,必须利用 limit 之类的操作限制 Stream 大小。

1
2
3
4
5
6
7
8
9
10
//Stream.generate()
Random seed = new Random();

Supplier<Integer>random = seed::nextInt; //seed.nextInt

Stream.generate(random).limit(10).forEach(System.out::println);

//使用IntStream
IntStream.generate(() ->(int) (System.nanoTime() % 100)).
limit(10).forEach(System.out::println);

4.使用Stream.iterate()
static Stream iterate(T seed, UnaryOperator f) 返回通过将函数f迭代应用于初始元素种子产生的无限顺序有序流,产生由种子f(种子),f(f(种子))等组成的流。
Stream中的第一个元素(位置0)将是提供的种子。 对于n> 0,位置n处的元素将是将函数f应用于位置n-1处的元素的结果。

iterate 跟 reduce 操作很像,接受一个种子值,和一个 UnaryOperator(例如 f)。然后种子值成为 Stream 的第一个元素,f(seed) 为第二个,f(f(seed)) 第三个,以此类推。

注意:与 Stream.generate 相仿,在 iterate 时候管道必须有 limit 这样的操作来限制 Stream 大小。

1
2
//Stream.iterate() 生产等差数列
Stream.iterate(0, n ->n + 3).limit(10). forEach(x ->System.out.print(x + " "));

完整实例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.devnp.java8.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class CreateStreamDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub

//从数组
String[] arr = { "program", "creek", "program", "creek", "java"};
Stream<String>stream = Stream.of(arr);

Stream<String>stream2 = Stream.of("program", "creek", "program", "creek", "java");

//从集合里面
List<String>strings = Arrays.asList("abc", "cbc", "bbc", "cbc", "uas","cctv", "cnc");

Stream<String>listStream = strings.stream();

//Stream.generate()
Random seed = new Random();

Supplier<Integer>random = seed::nextInt; //seed.nextInt

Stream.generate(random).limit(10).forEach(System.out::println);

//使用IntStream
IntStream.generate(() ->(int) (System.nanoTime() % 100)).
limit(10).forEach(System.out::println);

//Stream.iterate() 生产等差数列
Stream.iterate(0, n ->n + 3).limit(10). forEach(x ->System.out.print(x + " "));

}

}

用 Collectors 来进行 reduction 操作

java.util.stream.Collectors 收集者实施各种有用的还原操作,如将元素累积到收藏中,根据各种标准汇总元素等,主要作用就是辅助进行各类有用的 reduction 操作.

groupingBy/partitioningBy

例如统计字符串出现的次数:

1
2
3
List<String>strings = Arrays.asList("abc", "cbc", "abc", "cbc", "uas","cctv", "cnc");

Map<String, Long>result = strings.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

例如找出“abc”字符串:

1
2
List<String>strings = Arrays.asList("abc", "cbc", "abc", "cbc", "uas","cctv", "cnc");
Map<Boolean, List<String&gt;>result2 = strings.stream().collect(Collectors.partitioningBy(p ->p.equals("abc")));

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.devnp.java8.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class CollectorsDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub

List<String>strings = Arrays.asList("abc", "cbc", "abc", "cbc", "uas","cctv", "cnc");

Map<String, Long>result = strings.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

System.out.println(result);

System.out.println("---------------");

Map<Boolean, List<String&gt;>result2 = strings.stream().collect(Collectors.partitioningBy(p ->p.equals("abc")));

System.out.println(result2);
}

}

运行结果:
[code lang=”text”]
{abc=2, cbc=2, uas=1, cnc=1, cctv=1}


{false=[cbc, cbc, uas, cctv, cnc], true=[abc, abc]}

```

总结

  1. Stream 不是数据结构,没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据。
  2. Stream 也绝不修改自己所封装的底层数据结构的数据。
  3. Stream 的操作必须以 lambda 表达式为参数
  4. 不支持索引访问
  5. 惰性化
  6. Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。
  7. 当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。
  8. 集合有固定大小,Stream 则不必, 可以是无限的.