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); }
|
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); }
|
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); }
|
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); }
|
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); boolean result1 = list.stream().allMatch((i -> i % 2 == 0)); boolean result2 = list.stream().anyMatch((i -> i % 2 == 0)); boolean result3 = list.stream().noneMatch((i -> i % 2 == 0)); System.out.println(result1); System.out.println(result2); System.out.println(result3); }
|
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); }
|
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); }
|
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); }
|
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); }
|
这里用到 T reduce(T identity, BinaryOperator<T> accumulator); 其中 identity 是作为此次运算的起始值(种子),然后依据 accumulator 提供的运算规则将 Stream 中的元素逐个逐个与前面的组合起来。这相当于:
1 2 3 4 5
| int result = 0; 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<Integer> optional = list.stream().reduce((n1, n2) -> n1 + n2); Integer result = optional.get(); System.out.println(result); }
|
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); }
|
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); }
|