侧边栏壁纸
博主头像
Setyg的博客

当秋风染红落叶的时候,就是新生~

  • 累计撰写 86 篇文章
  • 累计创建 66 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Java Stream API 常用方法详解:从入门到精通

Setyg
2026-09-09 / 0 评论 / 0 点赞 / 9 阅读 / 0 字

Java Stream API 常用方法实践

Java Stream API 自 Java 8 引入以来,彻底改变了我们处理集合数据的方式。它提供了一种声明式、函数式的数据处理方式,使代码更加简洁、易读且高效。本文将详细介绍 Stream API 的常用方法,并通过实际示例展示其强大功能。

Stream API 基础

Stream 是一种可以让你以声明式方式处理数据序列的抽象概念。它不是数据结构,而是对数据源的一种视图,可以执行各种操作来转换或处理数据。

Stream 常用方法分类

1. 创建 Stream

// 从集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();

// 从数组创建
String[] array = {"a", "b", "c"};
Stream<String> stream2 = Arrays.stream(array);

// 使用 Stream.of()
Stream<String> stream3 = Stream.of("a", "b", "c");

// 使用 Stream.builder()
Stream<String> stream4 = Stream.<String>builder()
    .add("a")
    .add("b")
    .add("c")
    .build();

// 无限流
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1);

2. 中间操作(Intermediate Operations)

过滤操作

// filter - 过滤满足条件的元素
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evenNumbers = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.toList());
// 结果: [2, 4, 6]

// distinct - 去重
List<Integer> duplicates = Arrays.asList(1, 2, 2, 3, 3, 3, 4);
List<Integer> unique = duplicates.stream()
    .distinct()
    .collect(Collectors.toList());
// 结果: [1, 2, 3, 4]

// limit - 限制流的大小
List<Integer> limited = numbers.stream()
    .limit(3)
    .collect(Collectors.toList());
// 结果: [1, 2, 3]

// skip - 跳过前n个元素
List<Integer> skipped = numbers.stream()
    .skip(3)
    .collect(Collectors.toList());
// 结果: [4, 5, 6]

映射操作

// map - 将每个元素转换为另一种形式
List<String> words = Arrays.asList("apple", "banana", "cherry");
List<Integer> lengths = words.stream()
    .map(String::length)
    .collect(Collectors.toList());
// 结果: [5, 6, 6]

// flatMap - 将每个元素映射为一个流,然后将所有流合并
List<List<String>> nestedList = Arrays.asList(
    Arrays.asList("a", "b"),
    Arrays.asList("c", "d")
);
List<String> flattened = nestedList.stream()
    .flatMap(List::stream)
    .collect(Collectors.toList());
// 结果: ["a", "b", "c", "d"]

// peek - 在流中每个元素被处理时执行操作(主要用于调试)
List<String> result = words.stream()
    .peek(System.out::println)
    .map(String::toUpperCase)
    .collect(Collectors.toList());

排序操作

// sorted - 自然排序
List<Integer> unsorted = Arrays.asList(3, 1, 4, 1, 5, 9);
List<Integer> sorted = unsorted.stream()
    .sorted()
    .collect(Collectors.toList());
// 结果: [1, 1, 3, 4, 5, 9]

// sorted - 自定义排序
List<String> names = Arrays.asList("John", "Sarah", "Mark", "Tina");
List<String> sortedByNameLength = names.stream()
    .sorted(Comparator.comparingInt(String::length))
    .collect(Collectors.toList());
// 结果: ["Mark", "John", "Sarah", "Tina"]

截断操作(JDK 9+)

// takeWhile - 取满足条件的元素,直到条件不满足
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 1);
List<Integer> taken = numbers.stream()
    .takeWhile(n -> n < 4)
    .collect(Collectors.toList());
// 结果: [1, 2, 3]

// dropWhile - 丢弃满足条件的元素,直到条件不满足
List<Integer> dropped = numbers.stream()
    .dropWhile(n -> n < 4)
    .collect(Collectors.toList());
// 结果: [4, 5, 1]

3. 终端操作(Terminal Operations)

匹配操作

// anyMatch - 检查是否至少有一个元素满足条件
boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);
// 结果: true

// allMatch - 检查是否所有元素都满足条件
boolean allPositive = numbers.stream().allMatch(n -> n > 0);
// 结果: true

// noneMatch - 检查是否没有元素满足条件
boolean noNegative = numbers.stream().noneMatch(n -> n < 0);
// 结果: true

查找操作

// findFirst - 返回第一个元素(Optional)
Optional<Integer> first = numbers.stream().findFirst();
// 结果: Optional[1]

// findAny - 返回任意一个元素(Optional)
Optional<Integer> any = numbers.stream().findAny();
// 结果: Optional[某个元素]

统计操作

// count - 计算元素数量
long count = numbers.stream().count();
// 结果: 6

// min - 找到最小值
Optional<Integer> min = numbers.stream().min(Integer::compareTo);
// 结果: Optional[1]

// max - 找到最大值
Optional<Integer> max = numbers.stream().max(Integer::compareTo);
// 结果: Optional[9]

归约操作

// reduce - 将流归约为一个值
int sum = numbers.stream().reduce(0, Integer::sum);
// 结果: 24

// reduce - 带初始值的归约
int product = numbers.stream().reduce(1, (a, b) -> a * b);
// 结果: 1080

// reduce - 无初始值的归约(返回Optional)
Optional<Integer> sumOptional = numbers.stream().reduce(Integer::sum);

收集操作

// collect - 收集到集合
List<Integer> collectedList = numbers.stream().collect(Collectors.toList());
Set<Integer> collectedSet = numbers.stream().collect(Collectors.toSet());
Map<Integer, String> collectedMap = numbers.stream()
    .collect(Collectors.toMap(n -> n, n -> "Number " + n));

// collect - 自定义收集器
String joined = numbers.stream()
    .map(String::valueOf)
    .collect(Collectors.joining(", "));
// 结果: "1, 2, 3, 4, 5, 9"

// collect - 分组
Map<Boolean, List<Integer>> grouped = numbers.stream()
    .collect(Collectors.groupingBy(n -> n % 2 == 0));
// 结果: {false=[1, 3, 5, 9], true=[2, 4]}

// collect - 分区
Map<Boolean, List<Integer>> partitioned = numbers.stream()
    .collect(Collectors.partitioningBy(n -> n > 3));
// 结果: {false=[1, 2, 3], true=[4, 5, 9]}

并行流

// parallelStream - 并行处理
List<Integer> parallelResult = numbers.parallelStream()
    .map(n -> n * 2)
    .collect(Collectors.toList());

实际应用示例

示例1:处理用户数据

class User {
    private String name;
    private int age;
    private String city;
    
    // 构造函数、getter和setter
}

List<User> users = // 用户列表

// 找出所有成年用户
List<User> adults = users.stream()
    .filter(user -> user.getAge() >= 18)
    .collect(Collectors.toList());

// 按城市分组统计用户数量
Map<String, Long> cityCount = users.stream()
    .collect(Collectors.groupingBy(User::getCity, Collectors.counting()));

// 计算平均年龄
double averageAge = users.stream()
    .mapToInt(User::getAge)
    .average()
    .orElse(0);

示例2:处理日志数据

List<LogEntry> logs = // 日志条目列表

// 找出错误日志
List<LogEntry> errors = logs.stream()
    .filter(log -> log.getLevel().equals("ERROR"))
    .collect(Collectors.toList());

// 按日期分组统计错误数量
Map<LocalDate, Long> errorCountByDate = logs.stream()
    .filter(log -> log.getLevel().equals("ERROR"))
    .collect(Collectors.groupingBy(
        log -> log.getTimestamp().toLocalDate(),
        Collectors.counting()
    ));

// 找出最频繁的错误类型
Optional<Map.Entry<String, Long>> mostFrequentError = logs.stream()
    .filter(log -> log.getLevel().equals("ERROR"))
    .collect(Collectors.groupingBy(LogEntry::getMessage, Collectors.counting()))
    .entrySet().stream()
    .max(Map.Entry.comparingByValue());

示例3:处理商品数据

class Product {
    private String name;
    private double price;
    private String category;
    
    // 构造函数、getter和setter
}

List<Product> products = // 商品列表

// 计算总价格
double total = products.stream()
    .mapToDouble(Product::getPrice)
    .sum();

// 按类别分组并计算每个类别的平均价格
Map<String, Double> avgPriceByCategory = products.stream()
    .collect(Collectors.groupingBy(
        Product::getCategory,
        Collectors.averagingDouble(Product::getPrice)
    ));

// 找出最贵的商品
Optional<Product> mostExpensive = products.stream()
    .max(Comparator.comparingDouble(Product::getPrice));

性能考虑

1. 并行流 vs 顺序流:对于大型数据集,并行流可以提高性能,但对于小型数据集,顺序流可能更快。

2. 中间操作的延迟执行:Stream 操作是延迟执行的,只有在终端操作时才会实际处理数据。

3. 避免不必要的装箱/拆箱:使用 mapToInt、mapToLong、mapToDouble 等专门的方法来避免装箱开销。

JDK 版本特性

如文档所述,不同 JDK 版本对 Stream API 的支持有所不同:

  • JDK 11:引入了 takeWhile()、dropWhile() 和 Stream.ofNullable()

  • JDK 17:引入了 Stream.toList() 简化收集操作

  • JDK 21:可能包含更多优化和新特性

总结

Java Stream API 提供了强大而灵活的数据处理能力,通过函数式编程风格使代码更加简洁和可读。掌握 Stream API 的各种方法可以显著提高你的 Java 编程效率和代码质量。

希望本文的示例能帮助你更好地理解和使用 Java Stream API!如有任何问题或建议,欢迎在评论区讨论。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区