JAVA8 Stream API 使用详解

Java 8 的 Stream API 是一个强大的工具,用于处理集合和数组的数据流操作。它提供了一种声明性、简洁且高效的方式来进行数据的过滤、转换、分组、统计等操作。本文将深入讲解 Stream API 的使用。


1. 什么是 Stream?

Stream 是一个数据管道,支持多种操作类型,包括:

  • 中间操作:返回一个新的 Stream,如 filter()map() 等。
  • 终端操作:触发计算并返回结果,如 forEach()collect() 等。

特点:

  1. 不存储数据,操作集合或数组的数据流。
  2. 支持链式调用。
  3. 延迟计算,只有在终端操作时才会执行。
  4. 可并行处理,提升性能。

2. 创建 Stream

常见创建方法:

  1. 从集合创建
  2. 从数组创建
  3. 从静态方法创建
  4. 自定义生成

示例代码:

import java.util.*;
import java.util.stream.*;

public class StreamCreation {
    
    
    public static void main(String[] args) {
    
    
        // 1. 从集合创建
        List<String> list = Arrays.asList("Alice", "Bob", "Charlie");
        Stream<String> streamFromList = list.stream();

        // 2. 从数组创建
        String[] array = {
    
    "A", "B", "C"};
        Stream<String> streamFromArray = Arrays.stream(array);

        // 3. 使用 Stream.of()
        Stream<Integer> streamFromValues = Stream.of(1, 2, 3, 4, 5);

        // 4. 无限流生成
        Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2).limit(5);
        infiniteStream.forEach(System.out::println); // 输出 0 2 4 6 8
    }
}

3. Stream 的操作类型

3.1 中间操作

中间操作返回一个新的 Stream,用于链式调用。

常见中间操作:
  1. filter() - 按条件过滤元素。
  2. map() - 将元素转换为另一种形式。
  3. sorted() - 对流进行排序。
  4. distinct() - 去重。
  5. limit()skip() - 截取或跳过元素。
示例代码:
public class StreamIntermediate {
    
    
    public static void main(String[] args) {
    
    
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Bob");

        names.stream()
            .filter(name -> name.startsWith("B")) // 过滤以 B 开头的
            .distinct()                            // 去重
            .sorted()                              // 排序
            .map(String::toUpperCase)              // 转换为大写
            .forEach(System.out::println);         // 输出
        // 输出:BOB
    }
}

3.2 终端操作

终端操作触发流的计算并返回结果。

常见终端操作:
  1. forEach() - 遍历元素。
  2. collect() - 将结果收集为集合或其他形式。
  3. count() - 计算元素个数。
  4. reduce() - 聚合操作。
  5. anyMatch() / allMatch() - 匹配检查。
示例代码:
import java.util.*;
import java.util.stream.Collectors;

public class StreamTerminal {
    
    
    public static void main(String[] args) {
    
    
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 1. collect
        List<Integer> evenNumbers = numbers.stream()
                                           .filter(n -> n % 2 == 0)
                                           .collect(Collectors.toList());
        System.out.println(evenNumbers); // 输出:[2, 4]

        // 2. count
        long count = numbers.stream().filter(n -> n > 3).count();
        System.out.println(count); // 输出:2

        // 3. reduce
        int sum = numbers.stream().reduce(0, Integer::sum);
        System.out.println(sum); // 输出:15

        // 4. allMatch
        boolean allPositive = numbers.stream().allMatch(n -> n > 0);
        System.out.println(allPositive); // 输出:true
    }
}

4. 高级用法:分组与分区

Collectors 提供了强大的工具来分组和分区数据。

示例代码:

import java.util.*;
import java.util.stream.*;

public class StreamGrouping {
    
    
    public static void main(String[] args) {
    
    
        List<String> items = Arrays.asList("apple", "banana", "orange", "apple", "orange", "banana", "apple");

        // 分组
        Map<String, Long> grouped = items.stream()
                                         .collect(Collectors.groupingBy(item -> item, Collectors.counting()));
        System.out.println(grouped); // 输出:{banana=2, orange=2, apple=3}

        // 分区
        Map<Boolean, List<String>> partitioned = items.stream()
                                                       .collect(Collectors.partitioningBy(item -> item.startsWith("a")));
        System.out.println(partitioned); // 输出:{false=[banana, orange, orange, banana], true=[apple, apple, apple]}
    }
}

5. 并行流

通过 parallelStream()parallel(),可以将流转换为并行流,以充分利用多核 CPU 的计算能力。

示例代码:

import java.util.*;

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()
                         .filter(n -> n % 2 == 0)
                         .reduce(0, Integer::sum);
        System.out.println(sum); // 输出:30
    }
}

6. 注意事项与优化建议

  1. 避免修改流中的数据:流操作应该是无副作用的。
  2. 尽量减少使用并行流:并行流适合计算密集型任务,对于小数据集或 IO 密集型任务,可能会降低性能。
  3. 善用方法引用:提升代码可读性。