Stream流
在 JDK 1.8 中,Stream API 是一个全新的抽象层,它允许你以声明式的方式处理数据集合(如列表、集合等)。Stream API 可以极大地提高代码的可读性和效率,尤其适合用于数据处理、过滤、映射和聚合等操作。
核心概念
- Stream(流):不是一个数据结构,而是一个来自数据源的元素队列并支持聚合操作。
- 数据源:流的来源,可以是集合、数组、I/O channel 等。
- 聚合操作:类似 filter、map、limit、reduce 等操作。
流的特性
- 不存储数据:流不是存储元素的数据结构,而是按需计算。
- 函数式风格:对流的操作会返回一个新的流,不会修改原数据。
- 延迟执行:多数流操作(如 filter、map)是延迟执行的,直到终端操作才会触发计算。
- 可消费性:流只能被消费一次,消费后需要重新生成流。
常见操作分类
中间操作(Intermediate Operations)
filter(Predicate)
:过滤不符合条件的元素。map(Function)
:将元素转换成另一种类型。flatMap(Function<T, Stream>)
:将一个流中的每个值都转换成另一个流,然后把所有流连接成一个流。distinct()
:去重。sorted()
:排序。limit(long maxSize)
:截断流,使其元素不超过给定数量。skip(long n)
:跳过前 n 个元素。
终端操作(Terminal Operations)
forEach(Consumer)
:对每个元素执行操作。collect(Collector)
:将流转换为其他形式,如集合或 Map。toArray()
:将流转换为数组。reduce(BinaryOperator)
:将流中的元素反复结合起来,得到一个值。count()
:返回流中元素的数量。anyMatch(Predicate)
:检查是否至少有一个元素匹配。allMatch(Predicate)
:检查是否所有元素都匹配。noneMatch(Predicate)
:检查是否没有元素匹配。findFirst()
:返回流中的第一个元素。findAny()
:返回流中的任意元素。
示例代码
下面是一些使用 Stream API 的常见示例:
import java.util.*;import java.util.stream.Collectors;import java.util.stream.Stream;public class StreamExample { public static void main(String[] args) { // 创建一个列表 List names = Arrays.asList(\"Alice\", \"Bob\", \"Charlie\", \"David\", \"Edward\"); // 1. 过滤和打印 System.out.println(\"长度大于 4 的名字:\"); names.stream() .filter(name -> name.length() > 4) .forEach(System.out::println); // 2. 映射和收集 List upperCaseNames = names.stream() .map(String::toUpperCase) .collect(Collectors.toList()); System.out.println(\"\\n转换为大写后的名字:\" + upperCaseNames); // 3. 排序和限制 System.out.println(\"\\n按字母顺序排序后的前三个名字:\"); names.stream() .sorted() .limit(3) .forEach(System.out::println); // 4. 匹配操作 boolean allLongNames = names.stream() .allMatch(name -> name.length() > 3); System.out.println(\"\\n所有名字长度都大于 3 吗?\" + allLongNames); // 5. 归约操作 Optional concatenated = names.stream().reduce((n1, n2) -> n1 + \", \" + n2); concatenated.ifPresent(s -> System.out.println(\"\\n连接后的名字:\" + s)); // 6. 数值流 List numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .mapToInt(Integer::intValue) .sum(); System.out.println(\"\\n数字总和:\" + sum); // 7. 创建流的其他方式 System.out.println(\"\\n生成 5 个随机数:\"); Random random = new Random(); random.doubles(5) .forEach(System.out::println); // 8. flatMap 示例 List<List> nestedList = Arrays.asList( Arrays.asList(\"a\", \"b\"), Arrays.asList(\"c\", \"d\") ); List flattenedList = nestedList.stream() .flatMap(List::stream) .collect(Collectors.toList()); System.out.println(\"\\n扁平化后的列表:\" + flattenedList); }}
并行流
Stream API 还支持并行流,可以利用多核处理器的优势进行并行操作:
// 并行流示例long count = names.parallelStream() .filter(name -> name.length() > 4) .count();System.out.println(\"\\n并行流处理:长度大于 4 的名字数量 = \" + count);
使用并行流时需要注意线程安全问题,并且不是所有场景下并行流都能提高性能。
Stream API 是 JDK 1.8 中非常强大的一个特性,它让数据处理变得更加简洁和高效。通过组合各种中间操作和终端操作,你可以轻松完成复杂的数据处理任务。