Stream流
- 1.Stream的特性
- 2.Stream操作步骤
-
- [2.1 创建Stream](#2.1 创建Stream)
- [2.2 中间操作](#2.2 中间操作)
-
- [2.2.1 筛选操作](#2.2.1 筛选操作)
- [2.2.2 映射操作](#2.2.2 映射操作)
- [2.2.3 排序操作](#2.2.3 排序操作)
- [2.2.4 拆分与匹配操作](#2.2.4 拆分与匹配操作)
- [2.2.5 映射到不同类型](#2.2.5 映射到不同类型)
- [2.3 终端操作](#2.3 终端操作)
-
- [2.3.1 迭代操作](#2.3.1 迭代操作)
- [2.3.2 收集操作](#2.3.2 收集操作)
- [2.3.3 归约操作](#2.3.3 归约操作)
- [2.3.4 匹配操作](#2.3.4 匹配操作)
- [2.3.5 查找操作](#2.3.5 查找操作)
- [2.3.6 最值操作](#2.3.6 最值操作)
- [2.3.7 转换操作](#2.3.7 转换操作)
1.Stream的特性
- 不存储数据
Stream不是一个数据存储的结构,它不会存储元素,而是通过管道将数据源的元素传递给操作。 - 不可变性
Stream不会修改源数据,例如filter不会将数据源中的数据删除,每次操作会生成一个新的Stream。 - 惰性求值
Stream的中间操作是延迟执行的,只有在遇到终端操作时才会执行。 - 只能遍历一次
Stream的元素只能访问一次,类似Iterator,操作没有回头路,如果你想从头重新访问流的元素,对不起,你得重新生成一个新的流。
Stream就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
2.Stream操作步骤
- 创建Stream
可以通过集合、数组、文件、函数等创建 Stream。 - 中间操作
中间操作用于将一个Stream转换成另一个Stream。它们是惰性求值的,也就是说只有在终端操作出现时才会执行。 - 终止操作
终端操作会触发Stream的实际计算,返回一个具体的结果或副作用。
2.1 创建Stream
- 通过集合创建
- 通过数组创建
- 通过值创建
- 通过方法创建
- 从文件中获得
1.通过集合创建
stream()
: 返回一个顺序流parallelStream()
: 返回一个并行流
顺序流
stream() 创建的是顺序流。在顺序流中,所有的操作都是按顺序执行的,即每个元素依次通过流的操作链。stream() 使用单线程处理数据
,所有操作都是在同一个线程中按顺序进行。
java
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream().forEach(System.out::println);
>>> 1 2 3 4 5(按顺序输出)
顺序流适合数据量较小或者不需要并行处理的场景。
并行流
parallelStream() 创建的是并行流。在并行流中,流中的元素可以被分成多个数据块,每个块由不同的线程并行处理。多线程执行:并行流会利用多个CPU核心进行并发处理,可以显著提高处理大数据集的性能。
java
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.parallelStream().forEach(System.out::println);
>>> 5 1 3 2 4 (可能是任意顺序,因为是并行执行)
并行流适合大数据量和 CPU 密集型的任务,它能够有效地利用多核 CPU 的计算能力。但并行流也有开销,如线程创建和线程调度,适合在大数据量处理时使用。
注意事项
- 并行流不适合所有场景,例如当你的操作对顺序有严格要求时(如累加、合并等),并行流可能产生错误的结果。
- 并行流的多线程操作可能会引发线程安全问题,尤其是在处理共享资源时,需要特别注意线程同步。
2.通过数组创建
能够处理对应基本类型的数组IntStream、LongStream、DoubleStream :
java
Arrays.stream(new int[]{1,2,3})
3.由值创建流
java
Stream<Integer> integerStream = Stream.of(1);
Stream<String> stringStream = Stream.of("1");
2.2 中间操作
这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
2.2.1 筛选操作
filter(Predicate<? super T> predicate)
根据指定的条件过滤元素,保留符合条件的元素。
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出: [2, 4, 6]
distinct()
去除 Stream 中的重复元素,基于 equals() 方法进行比较。
java
List<String> names = Arrays.asList("Alice", "Bob", "Alice", "Charlie");
List<String> uniqueNames = names.stream()
.distinct()
.collect(Collectors.toList());
System.out.println(uniqueNames); // 输出: [Alice, Bob, Charlie]
limit(long maxSize)
限制 Stream 中元素的数量,仅保留前 maxSize 个元素。
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> firstThree = numbers.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println(firstThree); // 输出: [1, 2, 3]
skip(long n)
跳过前 n 个元素,保留后续元素。
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> skipTwo = numbers.stream()
.skip(2)
.collect(Collectors.toList());
System.out.println(skipTwo); // 输出: [3, 4, 5]
2.2.2 映射操作
map(Function<? super T, ? extends R> mapper)
将每个元素应用一个函数,将元素逐一映射成另一个值。
java
List<String> words = Arrays.asList("hello", "world");
List<Integer> lengths = words.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println(lengths); // 输出: [5, 5]
flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
将每个元素应用一个函数,将元素映射成一个新的流,然后将这些流"展平"或合并成一个流(一对多的映射)。
java
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d"),
Arrays.asList("e", "f")
);
List<String> flatList = nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(flatList); // 输出: [a, b, c, d, e, f]
2.2.3 排序操作
sorted()
按照自然顺序对元素进行排序。
java
List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);
List<Integer> sortedNumbers = numbers.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedNumbers); // 输出: [1, 2, 3, 4, 5]
sorted(Comparator<? super T> comparator)
按照自定义比较器对元素进行排序。
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> sortedNames = names.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
System.out.println(sortedNames); // 输出: [Charlie, Bob, Alice]
2.2.4 拆分与匹配操作
takeWhile(Predicate<? super T> predicate)
从头开始保留满足条件的元素,一旦遇到第一个不满足条件的元素,终止处理。
java
List<Integer> numbers = Arrays.asList(2, 4, 6, 1, 8, 10);
List<Integer> taken = numbers.stream()
.takeWhile(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(taken); // 输出: [2, 4, 6]
dropWhile(Predicate<? super T> predicate)
跳过开头满足条件的元素,保留后续元素。
java
List<Integer> numbers = Arrays.asList(2, 4, 6, 1, 8, 10);
List<Integer> dropped = numbers.stream()
.dropWhile(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(dropped); // 输出: [1, 8, 10]
2.2.5 映射到不同类型
mapToInt(ToIntFunction<? super T> mapper)
将 Stream 元素映射为 IntStream。
java
List<String> words = Arrays.asList("hello", "world");
IntStream lengths = words.stream()
.mapToInt(String::length);
lengths.forEach(System.out::println); // 输出: 5 5
mapToDouble(ToDoubleFunction<? super T> mapper)
将 Stream 元素映射为 DoubleStream。
java
List<String> words = Arrays.asList("hello", "world");
DoubleStream doubleLengths = words.stream()
.mapToDouble(s -> (double) s.length());
doubleLengths.forEach(System.out::println); // 输出: 5.0 5.0
mapToLong(ToLongFunction<? super T> mapper)
将 Stream 元素映射为 LongStream。
java
List<String> words = Arrays.asList("hello", "world");
LongStream longLengths = words.stream()
.mapToLong(s -> (long) s.length());
longLengths.forEach(System.out::println); // 输出: 5 5
2.3 终端操作
2.3.1 迭代操作
forEach()
: 对流中的每个元素执行指定的操作。forEachOrdered()
: 在有序流上以遇到的顺序对每个元素执行指定的操作(即使在并行流中也是如此)。
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println); // 对每个元素执行操作
2.3.2 收集操作
collect()
这些操作用于将流的结果收集到不同的容器或数据结构中(例如,List、Set、Map)。常与 Collectors 一起使用。
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList()); // 将结果收集为 List
2.3.3 归约操作
reduce()
reduce() 是一个通用的归约操作,它将流中的元素通过累加器函数合并为一个结果值。通常用于聚合、求和、累积等操作。
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 使用有 identity 参数的 reduce
int sum = numbers.stream().reduce(0, Integer::sum);
System.out.println(sum); // 输出: 15
// 使用没有 identity 的 reduce
Optional<Integer> sumWithoutIdentity = numbers.stream().reduce(Integer::sum);
sumWithoutIdentity.ifPresent(System.out::println); // 输出: 15
List<String> words = Arrays.asList("Hello", "World", "Java");
String result = words.stream().reduce("", (a, b) -> a + " " + b);
System.out.println(result); // 输出: " Hello World Java"
count()
用于计算流中的元素总数。
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// 统计大于 3 的元素个数
long countGreaterThanThree = numbers.stream().filter(n -> n > 3).count();
System.out.println(countGreaterThanThree); // 输出: 3
summaryStatistics()
summaryStatistics() 是一个用于数值流的终端操作,提供对流中元素的统计信息,例如最大值、最小值、总和、平均值和数量。常与 IntStream、LongStream 和 DoubleStream 一起使用。
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
// 使用 mapToInt 将 Integer 转为 int
IntSummaryStatistics stats = numbers.stream()
.mapToInt(Integer::intValue)
.summaryStatistics();
System.out.println("Max: " + stats.getMax()); // 输出: Max: 9
System.out.println("Min: " + stats.getMin()); // 输出: Min: 1
System.out.println("Sum: " + stats.getSum()); // 输出: Sum: 45
System.out.println("Average: " + stats.getAverage()); // 输出: Average: 5.0
System.out.println("Count: " + stats.getCount()); // 输出: Count: 9
2.3.4 匹配操作
anyMatch()
判断流中的任意一个元素是否满足给定的条件。
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyMatch = numbers.stream().anyMatch(n -> n > 3);
System.out.println(anyMatch); // 输出: true
allMatch()
判断流中的所有元素是否都满足给定的条件。noneMatch()
判断流中的所有元素是否都不满足给定的条件。
2.3.5 查找操作
findFirst()
返回流中的第一个元素。
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Optional<String> firstName = names.stream().findFirst();
firstName.ifPresent(System.out::println); // 输出: Alice
findAny()
返回流中的任意一个元素,特别适用于并行流。在并行流中,findAny 可能比 findFirst 更高效,因为它可以直接返回找到的第一个可用结果。
2.3.6 最值操作
min()
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> min = numbers.stream().min(Integer::compareTo);
min.ifPresent(System.out::println); // 输出: 1
max()
2.3.7 转换操作
toArray()
将流中的元素转换为数组。
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
String[] namesArray = names.stream().toArray(String[]::new); // 转换为数组
System.out.println(Arrays.toString(namesArray)); // 输出: [Alice, Bob, Charlie]