Stream 流是简化集合和数组操作的一种编程方式,使得集合和数组的操作像水流一样流畅。
更多参考:https://www.yuque.com/zhangshuaiyin/java/java-8-stream-api
下面通过原理 +实战 的方式了解 Stream 的用法。
获取方式
- 集合:default Stream stream();
- 数组:
- Arrays.stream(T[] array);
- Stream.of(T… values); (可变参数可以接收数组作为参数)
// 1. 集合Collection<String> list=newArrayList<>();Stream<String> ss= list.stream();// 2. 数组String[] arrs=newString[]{"Java","Python","C"};Stream<String> arrs1=Arrays.stream(arrs);Stream<String> arrs2=Stream.of(arrs);
Stream 操作分类
-
中间操作(intermediate):通过一系列中间(Intermediate)方法,对数据集进行过滤、检索等数据集的再次处理。
- 中间操作的特点是方法返回值还是 Stream 类型,可以继续链式调用其他方法执行操作。
- 中间操作是对数据的加工,注意,中间操作是 lazy 操作,并不会立马启动,需要等待终止操作才会执行。
-
终止操作(Terminal):通过最终(terminal)方法完成对数据集中元素的处理。
- 终止操作的特点是方法返回值为 空 或者 一个其他类型的结果。
- 终止操作是 Stream 的启动操作,只有加上终止操作,Stream才会真正的开始执行。
- 无状态(Stateless):指元素的处理不受之前元素的影响;
- 有状态(Stateful):指该操作只有拿到所有元素之后才能继续下去。
- 非短路操作(Unshort-circuiting):指必须处理所有元素才能得到最终结果;
短路操作(Short-circuiting):指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。
测试集合
Stream 中间操作不会自己启动,所以测试中都会加上 forEach 终止操作来启动 Stream 流的执行。
List<String> list=Arrays.asList("Java","","Spring","Mysql","Python","","C++");
中间操作
filter
【中间操作】过滤元素,筛选 Stream 流中符合条件的元素,作为流返回。
- 定义:
Stream<T>filter(Predicate<?superT> predicate);
- 实例:找出集合中的空元素
list.stream().filter(String::isEmpty).forEach(System.out::println);
map
【中间操作】对 Stream 流中的元素执行指定操作后映射为新的值流返回(会改变之前的集合元素),相当于加工。
- 定义:
<R>Stream<R>map(Function<?superT,?extendsR> mapper);
- 实例:将集合中的元素变为大写
list.stream().map(String::toUpperCase).forEach(System.out::println);
peek
【中间操作】返回一个由该流的元素组成的流,另外在每个元素上执行提供的操作,因为元素从结果流中被消耗。(Consumer 没有返回值,不会改变原来 Stream 流中的值)
- 定义:
Stream<T>peek(Consumer<?superT> action);
- 实例:源码中的说明
@apiNote This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline:
此方法的存在主要是为了支持调试,您希望在其中查看元素流经管道中的某个点时的情况:
list.stream().filter(e-> e.length()>3).peek(e->System.out.println("Filtered value: "+ e)).map(String::toUpperCase).peek(e->System.out.println("Mapped value: "+ e)).forEach(System.out::println);
limit
【短路有状态中间操作】截取 Stream 流中前 maxSize 个 元素。
- 定义:
Stream<T>limit(long maxSize);
- 实例:取集合中前 4 个元素。
list.stream().limit(4).forEach(System.out::println);
skip
【有状态中间操作】在丢弃流的前 n 元素后,返回由该流的其余元素组成的流。 如果此流包含少于 n 元素,则将返回一个空流。
- 定义:
Stream<T>skip(long n);
- 实例:跳过集合中前 4 个元素。
list.stream().skip(4).forEach(System.out::println);
distinct
【有状态中间操作】返回由该流的不同元素(根据Object.equals(Object) )组成的流。
- 对于有序流,不同元素的选择是稳定的(对于重复元素,保留遇到顺序中最先出现的元素。)
- 对于无序流,没有稳定性保证。
- 定义:
Stream<T>distinct();
- 实例:去除集合中重复的元素。
list.stream().distinct().forEach(System.out::println);
sorted
【有状态中间操作】返回由该流的元素组成的流,按自然顺序排序。
- 如果此流的元素不是 Comparable ,则在执行终端操作时可能会抛出java.lang.ClassCastException 。
- 对于有序流,排序是稳定的。 对于无序流,没有稳定性保证。
- 定义:
Stream<T>sorted();Stream<T>sorted(Comparator<?superT> comparator);
- 实例:按照 自然排序/自然排序倒序 集合中的元素。
list.stream().sorted().forEach(System.out::println);// 还可以实现 Comparator 接口来自定义排序规则
list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
终止操作
forEach
【终止操作】遍历操作,依次遍历 Stream 流中的元素,并执行给定的行为。
- 定义:
voidforEach(Consumer<?superT> action);
- 实例:遍历集合中的元素
list.stream().forEach(System.out::println);// 集合只遍历可简写为 Collection 自带的 forEach() 方法// list.forEach(System.out::println);
toArray
【终止操作】返回一个包含此流元素的数组。
- 定义:
Object[]toArray();
- 实例:将集合转成数组。
list.stream().toArray();// 对于集合可简写为 Collection 自带的 toArray() 方法// list.toArray();
min/max
【终止操作】返回 Stream 流中最小/最大的元素
- 定义:
Optional<T>min(Comparator<?superT> comparator);Optional<T>max(Comparator<?superT> comparator);
- 实例:返回集合中最小/最大的元素
Optional<String> min= list.stream().min(Comparator.naturalOrder());System.out.println(min.get());Optional<String> max= list.stream().max(Comparator.naturalOrder());System.out.println(max.get());
count
【终止操作】返回此流中元素的计数。
- 定义:
longcount();
- 实例:统计集合中的元素个数
long size= list.stream().count();// 对于集合可简写为 Collection 自带的 size() 方法// list.size();
reduce
【终止操作】使用提供的标识值和关联累积函数对该流的元素执行归约,并返回归约后的值。
- 定义:
Treduce(T identity,BinaryOperator<T> accumulator);Optional<T>reduce(BinaryOperator<T> accumulator);<U>Ureduce(U identity,BiFunction<U,?superT,U> accumulator,BinaryOperator<U> combiner);
- 实例:将集合中的元素累加。
String result= list.stream().reduce("",(s1, s2)-> s1+ s2);// JavaSpringMysqlPythonC++Optional<String> result= list.stream().reduce((s1, s2)-> s1+ s2);
collect
【终止操作】将 Stream 流转换为其他形式,该操作主要作为进行中间操作后的可变规约操作。
- 定义:
<R>Rcollect(Supplier<R> supplier,BiConsumer<R,?superT> accumulator,BiConsumer<R,R> combiner);<R,A>Rcollect(Collector<?superT,A,R> collector);
- 实例:将 List 转成 Set 。
list.stream().collect(Collectors.toSet());// 连接字符串// String result = list.stream().collect(Collectors.joining("-"));
查找与匹配
anyMatch
【短路终止操作】如果流的任何元素与提供的 断言 匹配,则为 true ,否则为 false。
- 定义:
booleananyMatch(Predicate<?superT> predicate);
- 实例:判断集合中是否存在有长度大于 6 的元素。
boolean result= list.stream().anyMatch(s-> s.length()>6)// false
allMatch
【短路终止操作】Stream 流中所有元素都与提供的 断言匹配,则为 ture,否则为 false。
- 定义:
booleanallMatch(Predicate<?superT> predicate);
- 实例:判断集合中的元素长度是否都小于等于 6。
boolean result= list.stream().allMatch(s-> s.length()<=6);// true
noneMatch
【短路终止操作】Stream 流中的所有元素都与提供的 断言 不匹配,则返回 true,否则为 false。
- 定义:
booleannoneMatch(Predicate<?superT> predicate);
- 实例:判断集合中的元素长度是否都不满足大于 6。
boolean result= list.stream().noneMatch(s-> s.length()>6);// true
findFirst
【短路终止操作】返回 Stream 流中第一个元素。
- 定义:
Optional<T>findFirst();
- 实例:
Optional<String> first= list.stream().findFirst();String result= first.get();// Java
findAny
【短路终止操作】返回 Stream 流中第一个元素。
- 此操作的行为明显是不确定的; 可以自由选择流中的任何元素。
- 这是为了在并行操作中实现最大性能;
- 代价是对同一源的多次调用可能不会返回相同的结果。 (如果需要稳定的结果,请改用findFirst() 。)
- 定义:
Optional<T>findAny();
- 实例:
Optional<String> first= list.stream().findAny();String result= first.get();// JavaOptional<String> first= list.parallelStream().findAny();String result= first.get();// Python