Java 17 Stream 全面解析
简介
Java 17 作为 Java 生态系统中的一个重要版本,带来了许多实用的特性和改进,其中 Stream API 是 Java 8 引入的一个强大工具,在 Java 17 中依然发挥着重要作用。Stream API 提供了一种高效且简洁的方式来处理集合数据,它允许开发者以声明式的方式对数据进行过滤、映射、排序等操作,大大提高了代码的可读性和可维护性。本文将深入介绍 Java 17 Stream 的基础概念、使用方法、常见实践以及最佳实践,帮助读者更好地掌握这一强大的工具。
目录
- 基础概念
- 使用方法
- 常见实践
- 最佳实践
- 小结
- 参考资料
基础概念
什么是 Stream
Stream 是 Java 8 引入的一个抽象概念,它代表了一系列支持各种聚合操作的元素序列。Stream 本身并不存储数据,而是对数据源(如集合、数组等)进行操作,它提供了一种流式处理数据的方式,使得数据处理更加高效和简洁。
Stream 的特点
- 不存储数据:Stream 不存储元素,它只是对数据源进行操作。
- 一次性使用:Stream 只能被消费一次,一旦被使用,就不能再次使用。
- 延迟执行:Stream 的操作分为中间操作和终端操作,中间操作是延迟执行的,只有在终端操作被调用时,中间操作才会真正执行。
Stream 的操作类型
- 中间操作:返回一个新的 Stream,用于对数据进行过滤、映射等操作,如
filter()
、map()
、sorted()
等。 - 终端操作:触发 Stream 的执行,并产生一个结果或副作用,如
forEach()
、collect()
、count()
等。
使用方法
创建 Stream
可以通过多种方式创建 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.of() 创建 Stream
Stream<String> streamFromValues = Stream.of("apple", "banana", "cherry");
}
}
中间操作
中间操作返回一个新的 Stream,以下是一些常见的中间操作:
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, 6, 7, 8, 9, 10);
// 过滤操作,只保留偶数
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.toList();
System.out.println("Even numbers: " + evenNumbers);
// 映射操作,将每个元素乘以 2
List<Integer> doubledNumbers = numbers.stream()
.map(n -> n * 2)
.toList();
System.out.println("Doubled numbers: " + doubledNumbers);
// 排序操作,按降序排序
List<Integer> sortedNumbers = numbers.stream()
.sorted((a, b) -> b - a)
.toList();
System.out.println("Sorted numbers in descending order: " + sortedNumbers);
}
}
终端操作
终端操作触发 Stream 的执行,并产生一个结果或副作用,以下是一些常见的终端操作:
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class TerminalOperationsExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// forEach 操作,遍历每个元素
numbers.stream()
.forEach(n -> System.out.print(n + " "));
System.out.println();
// count 操作,统计元素个数
long count = numbers.stream()
.count();
System.out.println("Number of elements: " + count);
// findFirst 操作,查找第一个元素
Optional<Integer> firstElement = numbers.stream()
.findFirst();
System.out.println("First element: " + firstElement.orElse(0));
}
}
常见实践
数据过滤和筛选
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());
System.out.println("Long fruits: " + longFruits);
}
}
数据映射和转换
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());
System.out.println("Upper case words: " + upperCaseWords);
}
}
数据聚合和统计
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()
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum of numbers: " + sum);
}
}
最佳实践
合理使用中间操作和终端操作
尽量将多个中间操作组合在一起,避免频繁调用终端操作,因为中间操作是延迟执行的,可以提高性能。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class BestPracticeExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 组合多个中间操作
List<Integer> result = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * 2)
.collect(Collectors.toList());
System.out.println("Result: " + result);
}
}
避免使用副作用
在 Stream 操作中,尽量避免使用有副作用的操作,如修改外部变量等,因为 Stream 是为并行处理设计的,副作用可能会导致线程安全问题。
import java.util.Arrays;
import java.util.List;
public class AvoidSideEffectsExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 不使用副作用的方式计算总和
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum: " + sum);
}
}
小结
Java 17 Stream 是一个强大的工具,它提供了一种高效且简洁的方式来处理集合数据。通过本文的介绍,我们了解了 Stream 的基础概念、使用方法、常见实践以及最佳实践。在实际开发中,合理使用 Stream 可以提高代码的可读性和可维护性,同时也能提升程序的性能。希望本文能帮助读者更好地掌握 Java 17 Stream 的使用。
参考资料
- 《Effective Java》(第三版)
- 《Java 8 in Action》