Java Stream
Stream概述
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂查找、过滤和映射数据等操作。我们通常借助Stream API对集合数据进行操作。
简单说一下使用Stream时会发生的步骤:
1 | 获取一个数据源 -> 数据转换 -> 执行操作获取结果 |
获取一个数据源
Stream本身并不会存储数据,而是对数据源的一种抽象视图,它更像一个管道。许哟啊注意的是,Stream并不会改变原始数据。这里管道可以如何理解呢?就好比生产线上流动的传送带,Stream负责对这些材料进行加工处理。
1
2List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = list.stream(); // 创建数据源数据转换
数据转换通常会借助一些中间操作,例如:
map:将元素映射为新值。filter:过滤掉不符合条件的元素。等等…
1
Stream<Integer> NewStream = stream.filter(n -> n % 2 == 0);
执行操作获取结果
Stream的计算是惰性求值的,只有在执行终端操作时才会进行实际计算,例如:collect:收集结果到集合。forEach:遍历。- 等等…
1
List<Integer> result = NewStream.collect(Collectors.toList());
Stream使用
流的创建操作
1、 Stream可以通过Collection创建。
1 | List<String> list = new ArrayList<>(); |
这里解释一下stream和parallelStream的区别:
stream是顺序流,它是依照主线程的顺序对流进行操作。parallelStream是并行流,依照多线程并行执行的方式对流进行操作,因此不保证顺序。
2、Stream可以通过Array创建。
1 | int[] array = { 1, 3, 5, 6, 8 }; |
3、Stream可以通过静态方法:of()、iterate()、generate()创建。
1 | Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6); |
流的中间操作
筛选
筛选会按照一定规则校验流中的元素,将符合条件的元素提取至新的流中,常见的操作如下:
filter():根据条件过滤。limit(n):获取n个元素。skip(n):跳过n个元素。distinct():去除重复元素。
1 | Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14); |
映射
映射可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap
map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
1 | List<String> list = Arrays.asList("a,b,c", "1,2,3"); |
流的终止操作
遍历
1 | Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14); |
匹配
Stream中的元素是以Optional类型存在的。
1 | List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6); |
输出结果为
1 | 匹配第一个值:4 |
归约 reduce
通常分为三类:
Optional reduce
1 | Optional<T> reduce(BinaryOperator<T> accumulator) |
第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。
示例:
1 | List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); |
T reduce
1 | T reduce(T identity, BinaryOperator<T> accumulator) |
流程基本一致,不过第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。
1 | List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); |
U reduce
1 | <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner) |
主要用于并行流,我们知道并行流中数据会被拆分给多个线程进行执行,此时每个线程的处理流程会按照T reduce执行;第三个参数combiner,会将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行归约。
收集 Collector
顾名思义,Collector的职责就是将流中的数据重新归集到一起。
这里以toList()为例:
1 | Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14); |
查看collect方法声明:
1 |
|
再根据下方toList()返回值类型可以知道当前stream.collect()的返回类型是List<T>。
1 | public static <T> |
可以看到toList()返回值类型为Collector<T, ?, List<T>>,CollectorImpl实现了接口Collector<T, A, R>。
1 | static class CollectorImpl<T, A, R> implements Collector<T, A, R> |
CollectorImpl实现如下:
1 | CollectorImpl(Supplier<A> supplier, |
supplier:空的累加器。accumulator:累加操作。combiner:合并操作。characteristics:收集器特性。