Java8 中新引入的 Stream 和以往的 I/O 流是完全不同的两个东西Java8 中的 Stream 是对集合功能的增强它结合 Java8 中新引入的 Lambda 表达式可以使我们编写少量的代码就能够完成一些复杂的功能

你可以对 Stream 进行两种操作Intermediate 操作(中间操作)和 Terminal 操作(最终操作)

Intermediate 操作是将修改后的 Stream 返回给调用方因此对一个 Stream 可以使用零个或多个 Intermediate 操作

Terminal 操作是对 Stream 的最后一个操作此后该 Stream 无法再被操作一个 Stream 只能有一个 Terminal 操作

forEach

Terminal 操作用于遍历元素

1
2
3
4
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
list.stream().forEach(System.out::print); // 135246
}

filter

Intermediate 操作用于对 Stream 的每个元素进行判断符合判断的元素才会被留下来

1
2
3
4
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
list.stream().filter((i) -> i % 2 == 0).forEach(System.out::print); // 246
}

sorted

Intermediate 操作用于对 Stream 的元素进行自然排序

1
2
3
4
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
list.stream().sorted().forEach(System.out::print); // 123456
}

map

Intermediate 操作用于将原始 Stream 的每一个元素映射成任意类型的另外一个元素

1
2
3
4
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
list.stream().map((i) -> (char)('a' + i)).forEach(System.out::print); // bdfceg
}

match

Terminal 操作用于判断元素是否满足某种特定的条件

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
// allMatch : 所有元素符合条件才返回 true
boolean result1 = list.stream().allMatch((i -> i % 2 == 0));
// anyMatch : 只要有一个元素符合条件即返回 true
boolean result2 = list.stream().anyMatch((i -> i % 2 == 0));
// noneMatch : 所有元素都不符合条件才返回 true
boolean result3 = list.stream().noneMatch((i -> i % 2 == 0));
System.out.println(result1); // false
System.out.println(result2); // true
System.out.println(result3); // false
}

count

Terminal 操作用于统计 Stream 中元素的总数

1
2
3
4
5
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
long result = list.stream().filter((i) -> i % 2 == 0).count();
System.out.println(result); // 3
}

limit

Intermediate 操作用于取得 Stream 的前 n 个元素

1
2
3
4
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
list.stream().limit(3).forEach(System.out::print); // 135
}

skip

Intermediate 操作用于跳过 Stream 的前 n 个元素

1
2
3
4
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
list.stream().skip(3).forEach(System.out::print); // 246
}

reduce

Terminal 操作用于依据参数给定的 BinaryOperator 运算规则将 Stream 中的元素组合起来

BinaryOperator(二元操作)是一个函数式接口它继承于 BiFunction(二元函数)

BiFunction 与 Function 接口非常相似不同的是BiFunction 有两个输入参数而 Function 只有一个参数输入

BinaryOperator 继承于 BiFunction其目的仅仅是为了将两个输入参数声明为同一种类型而已以下为源码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
@FunctionalInterface
public interface BiFunction<T, U, R> {
... ...
}
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
... ...
}

使用 reduce 对 Stream 中的元素进行求和

1
2
3
4
5
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
Integer result = list.stream().reduce(0, (n1, n2) -> n1 + n2);
System.out.println(result); // 21
}

这里用到 T reduce(T identity, BinaryOperator<T> accumulator); 其中 identity 是作为此次运算的起始值(种子)然后依据 accumulator 提供的运算规则将 Stream 中的元素逐个逐个与前面的组合起来这相当于

1
2
3
4
5
int result = 0; // 参数 identity 指定的起始值
for (int item : list) {
result += item;
}
return result;

因为我们给定了起始值因此我们认为 Stream 中至少存在一个元素因此它总能返回一个具体的值

与它非常相似的还有一个方法 Optional<T> reduce(BinaryOperator<T> accumulator); 由于此方法中没有起始值参数当 Stream 中没有元素即空的 Stream此时会返回一个空的 Optional 对象以防止 NullPointerException 的发生这是两者之间的区别

1
2
3
4
5
6
7
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
// 没有起始值, 返回的是 Optional 对象
Optional<Integer> optional = list.stream().reduce((n1, n2) -> n1 + n2);
Integer result = optional.get();
System.out.println(result); // 21
}

min

Terminal 操作是一种特殊的 reduce由于 Stream 可能是空的返回值为 Optional

1
2
3
4
5
6
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
Optional<Integer> optional = list.stream().min(Integer::compareTo);
Integer result = optional.get();
System.out.println(result); // 1
}

max

Terminal 操作是一种特殊的 reduce由于 Stream 可能是空的返回值为 Optional

1
2
3
4
5
6
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
Optional<Integer> optional = list.stream().max(Integer::compareTo);
Integer result = optional.get();
System.out.println(result); // 6
}