Stream流是Java 8引入的一种对集合数据进行操作的工具,它使得我们能够以声明式的方式处理数据流。Stream
API主要用于对集合(如List
、Set
、Map
等)进行复杂的操作,如过滤、映射、归约等,而不需要显式地编写循环和条件判断。它采用了一种函数式编程风格,可以让代码更加简洁和易于维护。
1. Stream流的核心概念
Stream API的主要特点包括以下几点:
-
顺序和并行执行:Stream可以以顺序流或并行流的方式执行操作。顺序流按照顺序处理数据,而并行流可以利用多核处理器并发处理数据,提高性能。
-
惰性求值:Stream的中间操作是惰性求值的,即这些操作不会立即执行,只有在执行终端操作时才会触发对数据流的实际处理。
-
不可变性:Stream本身是不可变的,每次对Stream进行操作都会返回一个新的Stream对象,而不会修改原始的数据源。
2. Stream流的操作类型
Stream流的操作分为两种类型:中间操作和终端操作。
2.1 中间操作 (Intermediate Operations)
中间操作是对流中的元素进行转换或过滤的操作,这些操作总是返回一个新的Stream,因此可以链式调用。常见的中间操作包括:
-
filter(Predicate<? super T> predicate)
: 对流中的元素进行过滤,只保留满足条件的元素。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> evenNumbers = numbers.stream() .filter(n -> n % 2 == 0);
-
map(Function<? super T, ? extends R> mapper)
: 将流中的每个元素映射到另一个元素,通常用于数据转换。List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> upperCaseStrings = strings.stream() .map(String::toUpperCase);
-
flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
: 将每个元素映射为一个流,并将这些流合并为一个流。常用于处理嵌套的集合结构。List<List<String>> listOfLists = Arrays.asList( Arrays.asList("a", "b"), Arrays.asList("c", "d")); Stream<String> flatStream = listOfLists.stream() .flatMap(Collection::stream);
-
distinct()
: 去除流中重复的元素。List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5); Stream<Integer> distinctNumbers = numbers.stream().distinct();
-
sorted()
: 对流中的元素进行排序,默认使用自然排序,也可以传入自定义的比较器。List<Integer> numbers = Arrays.asList(3, 5, 1, 2, 4); Stream<Integer> sortedNumbers = numbers.stream().sorted();
-
limit(long maxSize)
: 截取流中前maxSize
个元素。Stream<Integer> limitedNumbers = numbers.stream().limit(3);
-
skip(long n)
: 跳过流中的前n
个元素。Stream<Integer> skippedNumbers = numbers.stream().skip(2);
2.2 终端操作 (Terminal Operations)
终端操作会触发流的处理,并生成最终的结果。常见的终端操作包括:
-
forEach(Consumer<? super T> action)
: 对流中的每个元素执行给定的操作(消费元素)。numbers.stream().forEach(System.out::println);
-
collect(Collector<? super T, A, R> collector)
: 将流中的元素收集到某种集合或结果中(如List
、Set
、Map
等)。List<String> resultList = strings.stream() .map(String::toUpperCase) .collect(Collectors.toList());
-
toArray()
: 将流中的元素收集到一个数组中。String[] stringArray = strings.stream().toArray(String[]::new);
-
reduce(BinaryOperator<T> accumulator)
: 将流中的元素通过累积函数合并为一个结果,通常用于求和、乘积等操作。int sum = numbers.stream().reduce(0, Integer::sum);
-
count()
: 返回流中的元素数量。long count = numbers.stream().count();
-
anyMatch(Predicate<? super T> predicate)
: 检查是否有任意一个元素满足给定的条件。boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);
-
allMatch(Predicate<? super T> predicate)
: 检查是否所有元素都满足给定的条件。boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
-
noneMatch(Predicate<? super T> predicate)
: 检查是否没有元素满足给定的条件。boolean noneEven = numbers.stream().noneMatch(n -> n % 2 == 0);
-
findFirst()
: 返回流中的第一个元素的Optional
。Optional<Integer> firstNumber = numbers.stream().findFirst();
-
findAny()
: 返回流中的任意一个元素的Optional
,通常在并行流中使用。Optional<Integer> anyNumber = numbers.stream().findAny();
3. Stream的创建方式
Stream流可以通过多种方式创建,常见的创建方式包括:
-
从集合创建:
List<String> list = Arrays.asList("a", "b", "c"); Stream<String> stream = list.stream();
-
从数组创建:
String[] array = {"a", "b", "c"}; Stream<String> stream = Arrays.stream(array);
-
使用
Stream.of
方法:Stream<String> stream = Stream.of("a", "b", "c");
-
从文件创建:
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) { lines.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); }
-
生成流:
Stream<Integer> evenNumbers = Stream.iterate(0, n -> n + 2).limit(10);
-
并行流:并行流可以并发处理流中的数据。
Stream<String> parallelStream = list.parallelStream();
4. Stream流的并行化
Stream API支持并行化处理,即可以利用多核处理器并发处理数据流,从而提升性能。要使用并行流,只需要调用parallelStream()
或parallel()
方法。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.parallelStream()
.forEach(n -> System.out.println(n + " " + Thread.currentThread().getName()));
并行流适用于计算密集型任务或处理大规模数据集,但需要注意线程安全问题和性能的合理性。
5. Stream流的应用场景
-
数据过滤和转换:可以轻松地对数据进行过滤、映射和转换操作。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); List<String> upperCaseNames = names.stream() .filter(name -> name.startsWith("A")) .map(String::toUpperCase) .collect(Collectors.toList());
-
聚合和统计:可以对数据进行聚合和统计操作。
int sum = numbers.stream().reduce(0, Integer::sum); long count = numbers.stream().count();
-
并行处理:通过并行流可以利用多核处理器提高处理效率。
numbers.parallelStream().forEach(System.out::println);
-
处理复杂数据管道:通过链式调用多个Stream操作,可以构建复杂的数据处理管道。
List<String> result = list.stream() .filter(s -> s.length() > 1) .sorted() .map(String::toUpperCase) .collect(Collectors.toList());
总结
Stream API是Java 8引入的一项强大的工具