Java 8 Stream:强大的数据处理工具
简介
Java 8 引入了 Stream API,这是一个强大的功能,极大地简化了集合和数组的处理。Stream API 提供了一种声明式的方式来处理数据集合,允许你以更紧凑、更易读的代码执行复杂的数据操作,如过滤、映射、归约等。通过使用 Stream,你可以将数据处理逻辑与数据存储和遍历逻辑分离开来,提高代码的可读性和可维护性。
目录
- 基础概念
- 什么是 Stream
- Stream 与集合的区别
- 使用方法
- 创建 Stream
- 中间操作
- 终端操作
- 常见实践
- 过滤数据
- 映射数据
- 查找和匹配
- 归约操作
- 最佳实践
- 避免不必要的装箱和拆箱
- 合理使用并行流
- 结合 Stream 与 Lambda 表达式
- 小结
基础概念
什么是 Stream
Stream 是 Java 8 中引入的一个接口,它代表一个元素序列,可以对这些元素执行各种操作。Stream 不是数据结构,它并不存储数据,而是提供了一种对数据进行处理的方式。Stream 操作可以是顺序的,也可以是并行的。
Stream 与集合的区别
- 数据存储:集合是数据的存储结构,它负责存储和管理数据;而 Stream 并不存储数据,它只是对现有数据的一种处理视图。
- 遍历方式:集合通常使用迭代器或增强 for 循环进行遍历,这种遍历方式是命令式的;而 Stream 使用声明式的方式进行操作,你只需要描述要对数据执行的操作,而不需要关心具体的遍历过程。
- 执行时机:集合的操作是立即执行的;而 Stream 的操作是延迟执行的,只有在终端操作被调用时,中间操作才会被执行,这种特性被称为惰性求值。
使用方法
创建 Stream
-
从集合创建 ```java import java.util.Arrays; import java.util.List; import java.util.stream.Stream;
public class StreamExample { public static void main(String[] args) { List
list = Arrays.asList("apple", "banana", "cherry"); Stream stream = list.stream(); stream.forEach(System.out::println); } } 2. **从数组创建**
java import java.util.Arrays; import java.util.stream.Stream;public class StreamExample { public static void main(String[] args) { String[] array = {"apple", "banana", "cherry"}; Stream
stream = Arrays.stream(array); stream.forEach(System.out::println); } } 3. **使用 `Stream.of` 方法**
java import java.util.stream.Stream;public class StreamExample { public static void main(String[] args) { Stream
stream = Stream.of("apple", "banana", "cherry"); stream.forEach(System.out::println); } } ```
中间操作
中间操作会返回一个新的 Stream,并且是惰性求值的,只有在终端操作被调用时才会执行。常见的中间操作有: 1. 过滤(filter):根据条件过滤元素。 ```java import java.util.Arrays; import java.util.List; import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Stream<Integer> filteredStream = numbers.stream()
.filter(num -> num % 2 == 0);
filteredStream.forEach(System.out::println);
}
}
```
-
映射(map):将每个元素映射为另一个元素。 ```java import java.util.Arrays; import java.util.List; import java.util.stream.Stream;
public class StreamExample { public static void main(String[] args) { List
words = Arrays.asList("apple", "banana", "cherry"); Stream lengthStream = words.stream() .map(String::length); lengthStream.forEach(System.out::println); } } 3. **排序(sorted)**:对 Stream 中的元素进行排序。
java import java.util.Arrays; import java.util.List; import java.util.stream.Stream;public class StreamExample { public static void main(String[] args) { List
numbers = Arrays.asList(3, 1, 4, 1, 5, 9); Stream sortedStream = numbers.stream() .sorted(); sortedStream.forEach(System.out::println); } } ```
终端操作
终端操作会触发 Stream 的执行,并返回一个结果。常见的终端操作有: 1. 遍历(forEach):对 Stream 中的每个元素执行指定的操作。 ```java import java.util.Arrays; import java.util.List; import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
List<String> list = Arrays.asList("apple", "banana", "cherry");
list.stream()
.forEach(System.out::println);
}
}
```
-
收集(collect):将 Stream 中的元素收集到一个集合中。 ```java import java.util.Arrays; import java.util.List; import java.util.stream.Collectors;
public class StreamExample { public static void main(String[] args) { List
numbers = Arrays.asList(1, 2, 3, 4, 5); List squaredNumbers = numbers.stream() .map(num -> num * num) .collect(Collectors.toList()); System.out.println(squaredNumbers); } } 3. **归约(reduce)**:将 Stream 中的元素组合成一个值。
java import java.util.Arrays; import java.util.List; import java.util.stream.Stream;public class StreamExample { public static void main(String[] args) { List
numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .reduce(0, Integer::sum); System.out.println(sum); } } ```
常见实践
过滤数据
过滤数据是 Stream 中最常见的操作之一。例如,从一个整数列表中过滤出所有偶数:
import java.util.Arrays;
import java.util.List;
public class FilterExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
numbers.stream()
.filter(num -> num % 2 == 0)
.forEach(System.out::println);
}
}
映射数据
映射操作可以将一个 Stream 中的元素转换为另一种类型的元素。例如,将一个字符串列表中的每个字符串转换为其长度:
import java.util.Arrays;
import java.util.List;
public class MapExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry");
words.stream()
.map(String::length)
.forEach(System.out::println);
}
}
查找和匹配
查找和匹配操作可以用于检查 Stream 中是否存在满足条件的元素。例如,检查一个整数列表中是否存在大于 10 的元素:
import java.util.Arrays;
import java.util.List;
public class MatchExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 11, 5);
boolean exists = numbers.stream()
.anyMatch(num -> num > 10);
System.out.println(exists);
}
}
归约操作
归约操作可以将 Stream 中的元素组合成一个值。例如,计算一个整数列表的总和:
import java.util.Arrays;
import java.util.List;
public class ReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, Integer::sum);
System.out.println(sum);
}
}
最佳实践
避免不必要的装箱和拆箱
在使用 Stream 时,尽量使用原始类型的 Stream,如 IntStream
、LongStream
和 DoubleStream
,以避免不必要的装箱和拆箱操作,提高性能。
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.stream.IntStream;
public class PrimitiveStreamExample {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
IntSummaryStatistics stats = IntStream.of(numbers)
.summaryStatistics();
System.out.println("Count: " + stats.getCount());
System.out.println("Sum: " + stats.getSum());
System.out.println("Average: " + stats.getAverage());
System.out.println("Min: " + stats.getMin());
System.out.println("Max: " + stats.getMax());
}
}
合理使用并行流
并行流可以利用多核处理器的优势,提高数据处理的速度。但是,并行流也会带来一些开销,如线程创建和同步的开销。因此,在使用并行流时,需要根据数据量和计算复杂度来权衡利弊。
import java.util.Arrays;
import java.util.List;
public class ParallelStreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sum = numbers.parallelStream()
.reduce(0, Integer::sum);
System.out.println(sum);
}
}
结合 Stream 与 Lambda 表达式
Stream API 与 Lambda 表达式是 Java 8 的两大核心特性,结合使用它们可以使代码更加简洁和易读。通过 Lambda 表达式,你可以更方便地定义 Stream 操作的逻辑。
import java.util.Arrays;
import java.util.List;
public class StreamLambdaExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.map(num -> num * 2)
.filter(num -> num > 5)
.forEach(System.out::println);
}
}
小结
Java 8 Stream API 为集合和数组的处理提供了一种强大而灵活的方式。通过使用 Stream,你可以以声明式的方式编写更紧凑、更易读的代码,提高代码的可读性和可维护性。在实际应用中,需要根据具体的需求选择合适的 Stream 操作,并遵循最佳实践,以充分发挥 Stream API 的优势。希望本文能帮助你深入理解并高效使用 Java 8 Stream。