本章是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: 将每个数乘以 2
List<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
(第四期):线程池
什么问题都可以评论区留言,看见都会回复的
如果你觉得本篇文章对你有所帮助的,把“文章有帮助的”打在评论区
多多支持吧!!!
点赞加藏评论,是对小编莫大的肯定。抱拳了!