本章是Reactor核心-前置知识(第三期),主要讲解StreamAPI。Stream流可以抽象为工厂的流水线,整条流水线走完,数据就处理完了。StreamAPI可以抽象为流水线上的各种操作,比如筛选、转换、组合等。本文章只适合有基础或从业人员进行学习。如果觉得文章有用,就点赞加藏关注支持一下吧。
最佳实战:以后凡是你写for循环处理数据的都可以用StreamAPI进行替换;
一、Stream基础知识
- Stream Pipeline:流管道、流水线
- Intermediate Operations:中间操作
- Terminal Operation:终止操作
流管道组成:
- 一个数据源(可以是一个数组、集合、生成器函数、I/O管道)
- 零或多个中间操作(将一个流变形成另一个流)
- 一个终止操作(产生最终结果)
注意:流是惰性的;只有执行终止操作时才会对源数据进行计算,而且只在需要时才会消耗源元素;
Stream所有数据和操作被组合成流管道(流水线):声明式处理集合数据,包括筛选、转换、组合等.
二、创建流
API: of、builder、empty、ofNullable、generate、concat、集合.stream、just、range
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;public class StreamCreationExamples {public static void main(String[] args) {// 1. 使用Stream.of创建流Stream<Integer> streamOf = Stream.of(1, 2, 3, 4, 5);List<Integer> resultOf = streamOf.collect(Collectors.toList());System.out.println("Stream.of: " + resultOf);// 2. 使用Stream.builder创建流Stream.Builder<Integer> builder = Stream.builder();builder.add(6).add(7).add(8);Stream<Integer> streamBuilder = builder.build();List<Integer> resultBuilder = streamBuilder.collect(Collectors.toList());System.out.println("Stream.builder: " + resultBuilder);// 3. 使用Stream.empty创建空流Stream<Integer> emptyStream = Stream.empty();List<Integer> resultEmpty = emptyStream.collect(Collectors.toList());System.out.println("Stream.empty: " + resultEmpty);// 4. 使用Stream.ofNullable创建流(可能为空)Integer num = null;Stream<Integer> streamOfNullable = Stream.ofNullable(num);List<Integer> resultOfNullable = streamOfNullable.collect(Collectors.toList());System.out.println("Stream.ofNullable: " + resultOfNullable);// 5. 使用Stream.generate创建无限流(这里只取前5个元素示例)Stream<Double> generatedStream = Stream.generate(() -> Math.random());List<Double> resultGenerated = generatedStream.limit(5).collect(Collectors.toList());System.out.println("Stream.generate: " + resultGenerated);// 6. 使用Stream.concat连接两个流Stream<Integer> stream1 = Stream.of(1, 2, 3);Stream<Integer> stream2 = Stream.of(4, 5, 6);Stream<Integer> concatenatedStream = Stream.concat(stream1, stream2);List<Integer> resultConcat = concatenatedStream.collect(Collectors.toList());System.out.println("Stream.concat: " + resultConcat);// 7. 使用集合的stream方法创建流List<Integer> list = new ArrayList<>();list.add(7);list.add(8);list.add(9);Stream<Integer> streamFromList = list.stream();List<Integer> resultFromList = streamFromList.collect(Collectors.toList());System.out.println("集合.stream: " + resultFromList);// 8. 使用Stream.just(Java 9引入)创建单元素流(这里使用Optional来演示类似功能)java.util.Optional<Integer> optional = java.util.Optional.of(10);Stream<Integer> justStream = optional.stream();List<Integer> resultJust = justStream.collect(Collectors.toList());System.out.println("Stream.just(类似Optional.stream): " + resultJust);// 9. 使用IntStream.range创建整数范围的流(IntStream是Stream的特化)java.util.stream.IntStream rangeStream = java.util.stream.IntStream.range(1, 6);List<Integer> resultRange = rangeStream.boxed().collect(Collectors.toList());System.out.println("IntStream.range: " + resultRange);}
}
在上述代码中:
-
Stream.of
用于创建包含指定元素的流。 -
Stream.builder
允许逐步构建流,最后通过build
方法生成流。 -
Stream.empty
创建一个空流。 -
Stream.ofNullable
创建一个可能包含单个元素(如果参数不为null
)的流。 -
Stream.generate
生成一个无限流,通过提供的 Supplier 函数不断生成元素,这里使用limit
方法限制只取前几个元素。 -
Stream.concat
连接两个流。 -
集合的
stream
方法将集合转换为流。 -
Stream.just
(在示例中使用Optional.stream
演示类似功能)创建包含单个元素的流。 -
IntStream.range
创建一个包含指定范围内整数的流,这里使用boxed
方法IntStream
转换为Stream<Integer>
。
三、中间操作( intermediate operation)
API: filter、 map、mapToInt、mapToLong、mapToDouble flatMap、flatMapToInt、flatMapToLong、flatMapToDouble mapMulti、mapMultiToInt、mapMultiToLong、mapMultiToDouble、 parallel、unordered、onClose、sequential distinct、sorted、peek、limit、skip、takeWhile、dropWhile
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;public class StreamApiExamples {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 1. filter: 过滤出偶数List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());System.out.println("filter (even numbers): " + evenNumbers);// 2. map: 将每个数乘以 2List<Integer> doubledNumbers = numbers.stream().map(n -> n * 2).collect(Collectors.toList());System.out.println("map (doubled numbers): " + doubledNumbers);// 3. mapToInt: 将元素转换为 int 类型并计算总和int sum = numbers.stream().mapToInt(Integer::intValue).sum();System.out.println("mapToInt (sum): " + sum);// 4. mapToLong: 将元素转换为 long 类型并计算总和long longSum = numbers.stream().mapToLong(Integer::longValue).sum();System.out.println("mapToLong (long sum): " + longSum);// 5. mapToDouble: 将元素转换为 double 类型并计算平均值double average = numbers.stream().mapToDouble(Integer::doubleValue).average().orElse(0);System.out.println("mapToDouble (average): " + average);// 6. flatMap: 将嵌套列表展开List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2),Arrays.asList(3, 4),Arrays.asList(5, 6));List<Integer> flattenedList = nestedList.stream().flatMap(List::stream).collect(Collectors.toList());System.out.println("flatMap (flattened list): " + flattenedList);// 7. flatMapToInt: 将嵌套的 IntStream 展开List<IntStream> nestedIntStreams = Arrays.asList(IntStream.of(1, 2),IntStream.of(3, 4),IntStream.of(5, 6));int flatIntSum = nestedIntStreams.stream().flatMapToInt(s -> s).sum();System.out.println("flatMapToInt (sum of flattened IntStream): " + flatIntSum);// 8. flatMapToLong: 这里简单模拟将 IntStream 转换为 LongStream 并展开long flatLongSum = nestedIntStreams.stream().flatMapToLong(s -> s.asLongStream()).sum();System.out.println("flatMapToLong (sum of flattened LongStream): " + flatLongSum);// 9. flatMapToDouble: 这里简单模拟将 IntStream 转换为 DoubleStream 并展开double flatDoubleSum = nestedIntStreams.stream().flatMapToDouble(s -> s.asDoubleStream()).sum();System.out.println("flatMapToDouble (sum of flattened DoubleStream): " + flatDoubleSum);// 10. mapMulti (Java 16+): 生成多个结果List<Integer> mapMultiResult = numbers.stream().<Integer>mapMulti((n, consumer) -> {if (n % 2 == 0) {consumer.accept(n);consumer.accept(n * 2);}}).collect(Collectors.toList());System.out.println("mapMulti: " + mapMultiResult);// 11. mapMultiToInt (Java 16+): 生成多个 int 结果int mapMultiToIntSum = numbers.stream().mapMultiToInt((n, consumer) -> {if (n % 2 == 0) {consumer.accept(n);consumer.accept(n * 2);}}).sum();System.out.println("mapMultiToInt (sum): " + mapMultiToIntSum);// 12. mapMultiToLong (Java 16+): 生成多个 long 结果long mapMultiToLongSum = numbers.stream().mapMultiToLong((n, consumer) -> {if (n % 2 == 0) {consumer.accept(n);consumer.accept(n * 2);}}).sum();System.out.println("mapMultiToLong (sum): " + mapMultiToLongSum);// 13. mapMultiToDouble (Java 16+): 生成多个 double 结果double mapMultiToDoubleSum = numbers.stream().mapMultiToDouble((n, consumer) -> {if (n % 2 == 0) {consumer.accept(n);consumer.accept(n * 2);}}).sum();System.out.println("mapMultiToDouble (sum): " + mapMultiToDoubleSum);// 14. parallel: 并行处理流long parallelCount = numbers.parallelStream().filter(n -> n % 2 == 0).count();System.out.println("parallel (count of even numbers): " + parallelCount);// 15. unordered: 去除流的顺序约束List<Integer> unorderedList = numbers.stream().unordered().collect(Collectors.toList());System.out.println("unordered: " + unorderedList);// 16. onClose: 流关闭时执行操作Stream<Integer> streamWithClose = numbers.stream().onClose(() -> System.out.println("Stream is closed."));streamWithClose.collect(Collectors.toList());streamWithClose.close();// 17. sequential: 将并行流转换为顺序流long sequentialCount = numbers.parallelStream().sequential().filter(n -> n % 2 == 0).count();System.out.println("sequential (count of even numbers): " + sequentialCount);// 18. distinct: 去除重复元素List<Integer> distinctNumbers = Arrays.asList(1, 2, 2, 3, 3, 3).stream().distinct().collect(Collectors.toList());System.out.println("distinct: " + distinctNumbers);// 19. sorted: 对流元素进行排序List<Integer> sortedNumbers = numbers.stream().sorted().collect(Collectors.toList());System.out.println("sorted: " + sortedNumbers);// 20. peek: 用于调试,在每个元素上执行操作List<Integer> peekedNumbers = numbers.stream().peek(n -> System.out.println("Processing: " + n)).filter(n -> n % 2 == 0).collect(Collectors.toList());System.out.println("peek: " + peekedNumbers);// 21. limit: 限制流的元素数量List<Integer> limitedNumbers = numbers.stream().limit(3).collect(Collectors.toList());System.out.println("limit: " + limitedNumbers);// 22. skip: 跳过前几个元素List<Integer> skippedNumbers = numbers.stream().skip(3).collect(Collectors.toList());System.out.println("skip: " + skippedNumbers);// 23. takeWhile (Java 9+): 取满足条件的元素,直到不满足为止List<Integer> takenWhileNumbers = numbers.stream().takeWhile(n -> n < 5).collect(Collectors.toList());System.out.println("takeWhile: " + takenWhileNumbers);// 24. dropWhile (Java 9+): 丢弃满足条件的元素,直到不满足为止List<Integer> droppedWhileNumbers = numbers.stream().dropWhile(n -> n < 5).collect(Collectors.toList());System.out.println("dropWhile: " + droppedWhileNumbers);}
}
在上述代码中:
-
filter
:根据指定的条件过滤流中的元素,只保留满足条件的元素。 -
map
:将流中的每个元素按照指定的映射函数进行转换。 -
mapToInt
、mapToLong
、mapToDouble
:将流中的元素分别转换为int
、long
、double
类型的流。 -
flatMap
:将嵌套的流展开为一个单一的流。 -
flatMapToInt
、flatMapToLong
、flatMapToDouble
:将嵌套的特定类型流展开为对应的基本类型流。 -
mapMulti
及其变体(Java 16+):可以为每个输入元素生成多个输出元素。 -
parallel
:将流转换为并行流,以并行方式处理元素。 -
unordered
:去除流的顺序约束,允许并行处理时更高效。 -
onClose
:在流关闭时执行指定的操作。 -
sequential
:将并行流转换为顺序流。 -
distinct
:去除流中重复的元素。 -
sorted
:对流中的元素进行排序。 -
peek
:用于调试,在每个元素上执行指定的操作,同时保持流的连续性。 -
limit
:限制流中元素的数量。 -
skip
:跳过流中的前几个元素。 -
takeWhile
(Java 9+):取满足条件的元素,直到遇到不满足条件的元素为止。 -
dropWhile
(Java 9+):丢弃满足条件的元素,直到遇到不满足条件的元素为止。
四、终止操作(terminal operation)
API: forEach、forEachOrdered、toArray、reduce、collect、toList、min、 max、count、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;public class StreamApiMethodsExample {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 1. forEach: 对每个元素执行操作System.out.println("forEach:");numbers.stream().forEach(num -> System.out.print(num + " "));System.out.println();// 2. forEachOrdered: 按顺序对每个元素执行操作,在并行流中更能体现差异System.out.println("forEachOrdered:");numbers.parallelStream().forEachOrdered(num -> System.out.print(num + " "));System.out.println();// 3. toArray: 将流转换为数组Integer[] numberArray = numbers.stream().toArray(Integer[]::new);System.out.println("toArray: " + Arrays.toString(numberArray));// 4. reduce: 对流中的元素进行归约操作,这里求元素总和Optional<Integer> sumOptional = numbers.stream().reduce(Integer::sum);System.out.println("reduce (sum): " + sumOptional.orElse(0));// 5. collect: 使用收集器收集流中的元素,这里将元素收集到一个新的列表中List<Integer> collectedList = numbers.stream().collect(Collectors.toList());System.out.println("collect (to List): " + collectedList);// 6. toList: Java 16 引入的便捷方法,将流转换为不可变列表List<Integer> newList = numbers.stream().toList();System.out.println("toList: " + newList);// 7. min: 找出流中的最小值Optional<Integer> minOptional = numbers.stream().min(Integer::compareTo);System.out.println("min: " + minOptional.orElse(0));// 8. max: 找出流中的最大值Optional<Integer> maxOptional = numbers.stream().max(Integer::compareTo);System.out.println("max: " + maxOptional.orElse(0));// 9. count: 统计流中元素的数量long count = numbers.stream().count();System.out.println("count: " + count);// 10. anyMatch: 判断流中是否有任何元素满足条件boolean anyMatch = numbers.stream().anyMatch(num -> num > 5);System.out.println("anyMatch (any number > 5): " + anyMatch);// 11. allMatch: 判断流中所有元素是否都满足条件boolean allMatch = numbers.stream().allMatch(num -> num > 0);System.out.println("allMatch (all numbers > 0): " + allMatch);// 12. noneMatch: 判断流中是否没有元素满足条件boolean noneMatch = numbers.stream().noneMatch(num -> num < 0);System.out.println("noneMatch (no number < 0): " + noneMatch);// 13. findFirst: 找到流中的第一个元素Optional<Integer> firstOptional = numbers.stream().findFirst();System.out.println("findFirst: " + firstOptional.orElse(0));// 14. findAny: 找到流中的任意一个元素,在顺序流中通常返回第一个元素,在并行流中可能不同Optional<Integer> anyOptional = numbers.parallelStream().findAny();System.out.println("findAny: " + anyOptional.orElse(0));// 15. iterator: 获取流的迭代器Iterator<Integer> iterator = numbers.stream().iterator();System.out.print("iterator: ");while (iterator.hasNext()) {System.out.print(iterator.next() + " ");}System.out.println();}
}
在上述代码中:
-
forEach
:对流中的每个元素执行给定的操作,操作顺序不确定,尤其是在并行流中。 -
forEachOrdered
:与forEach
类似,但会按流中元素的顺序执行操作,在并行流中更能体现其与forEach
的差异。 -
toArray
:将流中的元素收集到一个数组中,需要指定数组的类型。 -
reduce
:通过指定的归约操作(如求和、求积等)将流中的元素合并为一个结果,返回一个Optional
对象,因为流可能为空。 -
collect
:使用收集器将流中的元素收集到一个集合或其他数据结构中,这里使用Collectors.toList()
将元素收集到一个列表中。 -
toList
:Java 16 引入的便捷方法,将流中的元素收集到一个不可变列表中。 -
min
:根据指定的比较器找出流中的最小值,返回一个Optional
对象。 -
max
:根据指定的比较器找出流中的最大值,返回一个Optional
对象。 -
count
:统计流中元素的数量。 -
anyMatch
:判断流中是否有任何元素满足给定的条件。 -
allMatch
:判断流中所有元素是否都满足给定的条件。 -
noneMatch
:判断流中是否没有元素满足给定的条件。 -
findFirst
:返回流中的第一个元素,返回一个Optional
对象。 -
findAny
:返回流中的任意一个元素,在顺序流中通常返回第一个元素,在并行流中可能返回不同的元素,返回一个Optional
对象。 -
iterator
:获取流的迭代器,允许以传统的迭代方式遍历流中的元素。
五、流与集合
- 集合关注高效数据管理和访问。
- 流没有提供直接访问或操作其元素的手段,关注声明性地描述源头数据的一系列操作。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ComplexStreamExample {public static void main(String[] args) {List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "avocado", "blueberry");List<String> result = words.stream()// 过滤长度大于5的单词.filter(word -> word.length() > 5)// 将单词转换为大写形式.map(String::toUpperCase)// 将每个单词拆分为字符,并放入新的流中.flatMap(word -> Arrays.stream(word.split("")))// 去重.distinct()// 按照字母顺序排序.sorted()// 在每个字符上执行某些操作,并打印调试信息.peek(System.out::println)// 取前4个字符.limit(4)// 跳过前两个字符.skip(2)// 使用takeWhile,保留小于'F'的字符.takeWhile(ch -> ch.charAt(0) < 'F')// 收集结果并转为列表.collect(Collectors.toList());System.out.println("Result: " + result);}
}
下期预告:Reactor核心-前置知识(第四期)
Reactor核心-前置知识一共有四期
(第一期):Lambda表达式
(第二期):Function函数式接口出入参定义
(第三期):StreamAPI
(第四期):线程池
什么问题都可以评论区留言,看见都会回复的
如果你觉得本篇文章对你有所帮助的,把“文章有帮助的”打在评论区
多多支持吧!!!
点赞加藏评论,是对小编莫大的肯定。抱拳了!