一、流的概念
定义
📕流是用于操作数据源(如集合、数组等)生成的元素序列的抽象数据结构。流就像花洒一样,通过不同的过滤器和形状来改变数据流的形式和处理方式。
特性
惰性执行
🍇流的中间操作(如 filter
, map
等)不会立即执行,而是在终端操作(如 forEach
, collect
等)触发时才执行。这种特性允许流在进行多个中间操作时,只遍历一次数据源,从而提高效率。
不存储数据
🍬流本身不存储数据,它只是数据的视图或操作的管道。流操作分为中间操作和终端操作。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class LazyExecution {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Jack", "Doe");
// 创建流并进行一系列中间操作
Stream<String> stream = names.stream()
.filter(name -> {
System.out.println("Filtering: " + name);
return name.startsWith("J");
})
.map(name -> {
System.out.println("Mapping: " + name);
return name.toUpperCase();
});
System.out.println("Before terminal operation");
// 终端操作开始时,中间操作才会执行
stream.forEach(System.out::println);
System.out.println("After terminal operation");
}
}
二、流的创建
从集合创建
// 通过调用stream()函数进行流的创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> streamFromList = list.stream();
从数组创建
// 通过调用Array中的stream()方法,将集合传进去进行流的创建
String[] array = ["a", "b", "c"];
Stream<String> streamFromArry = Arrays.stream(array);
使用 Stream.of()
方法
// 直接调用Stream.of()方法,传入若干字符串进行流的创建
Stream<String> streamOf = Stream.of("a", "b", "c");
三、流的操作
⌨流操作分为中间操作和终端操作。中间操作返回的是流本身,可以进行链式调用。终端操作返回的是结果(如 List、数组、计算值等)。
中间操作
filter
:过滤流中的元素。
list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);
map
:将元素映射到另一个形式。
list.stream().map(String::toUpperCase).forEach(System.out::println);
flatMap
:将每个元素映射为流,然后将这些流合并为一个流。
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d")
);
listOfLists.stream().flatMap(List::stream).forEach(System.out::println);
sorted
:对流中的元素进行排序。
list.stream().sorted().forEach(System.out::println);
distinct
:去除流中的重复元素。
list.stream().distinct().forEach(System.out::println);
limit
:截取流中的前 n 个元素。
list.stream().limit(2).forEach(System.out::println);
skip
:跳过流中的前 n 个元素。
list.stream().skip(2).forEach(System.out::println);
示例代码
import java.util.*;
import java.util.stream.*;
public class IntermediateOperations {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "a");
// filter
list.stream()
.filter(s -> s.startsWith("a"))
.forEach(System.out::println); // 输出: a, a
// map
list.stream()
.map(String::toUpperCase)
.forEach(System.out::println); // 输出: A, B, C, A
// sorted
list.stream()
.sorted()
.forEach(System.out::println); // 输出: a, a, b, c
// distinct
list.stream()
.distinct()
.forEach(System.out::println); // 输出: a, b, c
}
}
终端操作
forEach
:对流中的每个元素执行操作。
list.stream().forEach(System.out::println);
collect
:将流中的元素收集到集合、列表或映射中。
List<String> filteredList = list.stream()
.filter(s -> s.startsWith("a"))
.collect(Collectors.toList());
toArray
:将流中的元素转换为数组。
String[] array = list.stream().toArray(String[]::new);
reduce
:对流中的元素进行合并操作。
Optional<String> reduced = list.stream().reduce((s1, s2) -> s1 + "#" + s2);
count
:计算流中的元素数量。
long count = list.stream().count();
anyMatch
, allMatch
, noneMatch
:匹配流中的元素。
boolean anyMatch = list.stream().anyMatch(s -> s.startsWith("a"));
boolean allMatch = list.stream().allMatch(s -> s.length() == 1);
boolean noneMatch = list.stream().noneMatch(s -> s.startsWith("z"));
findFirst
,findAny
:查找流中的元素。
Optional<String> first = list.stream().findFirst();
Optional<String> any = list.stream().findAny();
示例代码
import java.util.*;
import java.util.stream.*;
public class TerminalOperations {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "a");
// forEach
list.stream()
.forEach(System.out::println); // 输出: a, b, c, a
// collect
List<String> filteredList = list.stream()
.filter(s -> s.startsWith("a"))
.collect(Collectors.toList());
System.out.println(filteredList); // 输出: [a, a]
// toArray
String[] array = list.stream()
.toArray(String[]::new);
System.out.println(Arrays.toString(array)); // 输出: [a, b, c, a]
// reduce
Optional<String> reduced = list.stream()
.reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println); // 输出: a#b#c#a
// count
long count = list.stream()
.count();
System.out.println(count); // 输出: 4
// anyMatch, allMatch, noneMatch
boolean anyMatch = list.stream()
.anyMatch(s -> s.startsWith("a"));
System.out.println(anyMatch); // 输出: true
boolean allMatch = list.stream()
.allMatch(s -> s.length() == 1);
System.out.println(allMatch); // 输出: true
boolean noneMatch = list.stream()
.noneMatch(s -> s.startsWith("z"));
System.out.println(noneMatch); // 输出: true
// findFirst, findAny
Optional<String> first = list.stream()
.findFirst();
first.ifPresent(System.out::println); // 输出: a
Optional<String> any = list.stream()
.findAny();
any.ifPresent(System.out::println); // 可能输出: a
}
}
四、流的并行处理
✌ 通过调用 parallelStream()
方法,可以将流转换为并行流,以提高性能。并行流将数据分割成多个块,并在多个线程中进行处理,从而加速计算过程。
import java.util.*;
import java.util.stream.*;
public class ParallelStream {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "d");
// 并行流
list.parallelStream()
.forEach(System.out::println); // 输出顺序不定
}
}
五、总结
- 流(Streams):提供了一种功能强大的数据处理方式,支持通过中间操作和终端操作对数据进行转换和处理。
- 中间操作:如
filter
,map
,sorted
等,支持链式调用,惰性执行。 - 终端操作:如
forEach
,collect
,reduce
等,触发流的处理并产生结果。 - 并行流:通过
parallelStream()
提供并行处理能力,适用于需要大量计算的场景。
通过合理使用流,能够提高代码的可读性和性能。流的操作符及其特性是现代 Java 编程中非常重要的知识点。