Java Streams 全面解析
简介
Java Streams 是 Java 8 引入的一个强大的新特性,它为处理集合数据提供了一种声明式的方式。通过使用 Streams,开发者可以更简洁、更高效地对集合进行过滤、映射、排序等操作,而无需编写繁琐的循环代码。本文将详细介绍 Java Streams 的基础概念、使用方法、常见实践以及最佳实践,帮助读者深入理解并高效使用这一特性。
目录
- 基础概念
- 什么是 Java Streams
- Stream 与 Collection 的区别
- 使用方法
- 创建 Stream
- 中间操作
- 终端操作
- 常见实践
- 过滤元素
- 映射元素
- 排序元素
- 聚合操作
- 最佳实践
- 避免重复使用 Stream
- 并行流的使用
- 延迟执行的利用
- 小结
- 参考资料
基础概念
什么是 Java Streams
Java Streams 是一个来自数据源的元素队列并支持聚合操作。这里的数据源可以是集合、数组、I/O 通道等。Stream 提供了一种高效且易于使用的方式来处理数据,它允许你以声明式的方式处理集合中的元素。
Stream 与 Collection 的区别
- 数据处理方式:Collection 主要用于存储和访问数据,而 Stream 则侧重于对数据的计算。
- 数据遍历:Collection 中的元素需要手动进行遍历,而 Stream 提供了自动遍历的功能。
- 延迟执行:Stream 是延迟执行的,只有在调用终端操作时才会真正执行中间操作。
使用方法
创建 Stream
Java 提供了多种创建 Stream 的方式,以下是一些常见的示例:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamCreationExample {
public static void main(String[] args) {
// 从集合创建 Stream
List<String> list = Arrays.asList("apple", "banana", "cherry");
Stream<String> streamFromList = list.stream();
// 从数组创建 Stream
String[] array = {"apple", "banana", "cherry"};
Stream<String> streamFromArray = Arrays.stream(array);
// 创建空 Stream
Stream<String> emptyStream = Stream.empty();
// 创建无限 Stream
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1);
}
}
中间操作
中间操作是指在 Stream 上进行的一系列操作,这些操作不会立即执行,而是返回一个新的 Stream。常见的中间操作包括 filter
、map
、sorted
等。
import java.util.Arrays;
import java.util.List;
public class IntermediateOperationsExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 过滤操作
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.toList();
// 映射操作
List<Integer> squaredNumbers = numbers.stream()
.map(n -> n * n)
.toList();
// 排序操作
List<Integer> sortedNumbers = numbers.stream()
.sorted()
.toList();
}
}
终端操作
终端操作是指在 Stream 上进行的最后一个操作,它会触发中间操作的执行,并返回一个结果。常见的终端操作包括 forEach
、collect
、reduce
等。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class TerminalOperationsExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// forEach 操作
numbers.stream()
.forEach(System.out::println);
// collect 操作
List<Integer> squaredNumbers = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
// reduce 操作
int sum = numbers.stream()
.reduce(0, Integer::sum);
}
}
常见实践
过滤元素
过滤操作是指根据指定的条件筛选出符合条件的元素。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FilteringExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
// 过滤出长度大于 5 的水果
List<String> longFruits = fruits.stream()
.filter(fruit -> fruit.length() > 5)
.collect(Collectors.toList());
}
}
映射元素
映射操作是指将 Stream 中的每个元素转换为另一个元素。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MappingExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("hello", "world");
// 将每个单词转换为大写
List<String> upperCaseWords = words.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
}
}
排序元素
排序操作是指对 Stream 中的元素进行排序。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class SortingExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);
// 对数字进行升序排序
List<Integer> sortedNumbers = numbers.stream()
.sorted()
.collect(Collectors.toList());
}
}
聚合操作
聚合操作是指将 Stream 中的元素合并为一个结果。
import java.util.Arrays;
import java.util.List;
public class AggregationExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 计算数字的总和
int sum = numbers.stream()
.reduce(0, Integer::sum);
// 计算数字的最大值
int max = numbers.stream()
.reduce(Integer.MIN_VALUE, Integer::max);
}
}
最佳实践
避免重复使用 Stream
Stream 是一次性使用的,一旦调用了终端操作,就不能再使用该 Stream 进行其他操作。因此,在需要多次使用 Stream 时,应该创建新的 Stream。
import java.util.Arrays;
import java.util.List;
public class AvoidReusingStreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 第一次使用 Stream
long count = numbers.stream().count();
// 第二次使用 Stream,需要重新创建
int sum = numbers.stream().reduce(0, Integer::sum);
}
}
并行流的使用
并行流可以利用多核处理器的优势,提高 Stream 操作的性能。但是,并行流也会带来一定的开销,因此在使用并行流时需要谨慎。
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);
// 使用并行流计算总和
int sum = numbers.parallelStream().reduce(0, Integer::sum);
}
}
延迟执行的利用
Stream 的中间操作是延迟执行的,只有在调用终端操作时才会真正执行。因此,可以利用这一特性,在中间操作中进行多次转换,而不会立即消耗资源。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class LazyEvaluationExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 中间操作不会立即执行
var stream = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n);
// 调用终端操作,触发中间操作的执行
List<Integer> result = stream.collect(Collectors.toList());
}
}
小结
Java Streams 是 Java 8 引入的一个强大的新特性,它为处理集合数据提供了一种声明式的方式。通过使用 Streams,开发者可以更简洁、更高效地对集合进行过滤、映射、排序等操作。本文介绍了 Java Streams 的基础概念、使用方法、常见实践以及最佳实践,希望能帮助读者深入理解并高效使用这一特性。