Java工具 -- Stream流

引言

Java Stream API 是 Java 8 中引入的一个强大工具,它为集合处理提供了一种高效且易于理解的方式。Stream API 允许我们以声明性的方式处理数据,并支持复杂的数据处理操作,如过滤、映射、排序和聚合等。本文将详细探讨 Java Stream 流的基本概念、常用操作、实际应用场景以及代码示例。

1. 什么是 Stream?

在 Java 中,Stream 是对集合对象进行操作的一种抽象。它并不是一个数据结构,而是对数据源(如集合、数组等)进行操作的一种方式。Stream 可以处理大量数据,使用懒惰计算,并能有效利用多核架构。

1.1 Stream 的特性

  • 顺序性:Stream 保持了数据的顺序,操作的顺序与数据源的顺序一致。
  • 懒惰求值:Stream 操作通常是懒惰的,只有在需要结果时才会执行计算。
  • 可消费性:Stream 只能被消费一次,消费后不能再被重用。
  • 多核支持:可以轻松地将流操作并行化,提高性能。

2. 创建 Stream

Stream 可以从多种数据源创建,最常见的是从集合(如 List、Set)和数组创建。

2.1 从集合创建 Stream

javaCopy Code
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); List<String> filteredNames = names.stream() .filter(name -> name.startsWith("A")) .collect(Collectors.toList()); System.out.println(filteredNames); // 输出: [Alice] } }

2.2 从数组创建 Stream

javaCopy Code
import java.util.stream.Stream; public class ArrayStreamExample { public static void main(String[] args) { String[] array = {"One", "Two", "Three", "Four"}; Stream<String> stream = Arrays.stream(array); stream.forEach(System.out::println); // 输出: One, Two, Three, Four } }

3. Stream 的常用操作

Stream 提供了多种操作,包括中间操作和终端操作。中间操作返回一个新的 Stream,可以链式调用,而终端操作则触发计算并返回结果。

3.1 中间操作

3.1.1 filter()

用于筛选出满足条件的元素。

javaCopy Code
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); List<String> filteredNames = names.stream() .filter(name -> name.length() > 3) .collect(Collectors.toList()); System.out.println(filteredNames); // 输出: [Alice, Charlie, David]

3.1.2 map()

用于对每个元素进行转换。

javaCopy Code
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); List<Integer> nameLengths = names.stream() .map(String::length) .collect(Collectors.toList()); System.out.println(nameLengths); // 输出: [5, 3, 7]

3.1.3 sorted()

用于对元素进行排序。

javaCopy Code
List<String> names = Arrays.asList("Charlie", "Alice", "Bob"); List<String> sortedNames = names.stream() .sorted() .collect(Collectors.toList()); System.out.println(sortedNames); // 输出: [Alice, Bob, Charlie]

3.2 终端操作

3.2.1 collect()

将 Stream 的结果收集到集合中。

javaCopy Code
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); Set<String> nameSet = names.stream() .collect(Collectors.toSet()); System.out.println(nameSet); // 输出: [Alice, Bob, Charlie]

3.2.2 forEach()

对每个元素执行指定的操作。

javaCopy Code
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream().forEach(System.out::println); // 输出每个名字

3.2.3 reduce()

用于归约操作,将流中的元素聚合为单个值。

javaCopy Code
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Integer sum = numbers.stream() .reduce(0, Integer::sum); System.out.println(sum); // 输出: 15

4. 实际应用场景

4.1 数据过滤和处理

在处理大量数据时,使用 Stream API 可以简化过滤和处理逻辑。例如,从业务数据中筛选出特定用户。

javaCopy Code
class User { private String name; private int age; // Constructor, getters and setters } List<User> users = Arrays.asList( new User("Alice", 30), new User("Bob", 20), new User("Charlie", 25) ); List<String> userNames = users.stream() .filter(user -> user.getAge() > 21) .map(User::getName) .collect(Collectors.toList()); System.out.println(userNames); // 输出: [Alice, Charlie]

4.2 数据分组

使用 Collectors.groupingBy() 方法可以按照某个属性对数据进行分组。

javaCopy Code
Map<Integer, List<User>> groupedByAge = users.stream() .collect(Collectors.groupingBy(User::getAge)); groupedByAge.forEach((age, userList) -> { System.out.println("Age: " + age); userList.forEach(user -> System.out.println(" - " + user.getName())); });

4.3 数据统计

Stream API 支持对数据进行统计操作,例如求平均值、最大值、最小值等。

javaCopy Code
double averageAge = users.stream() .mapToInt(User::getAge) .average() .orElse(0); System.out.println("Average Age: " + averageAge); // 输出: Average Age: 25.0

4.4 排序和去重

Stream 可以轻松对数据进行排序和去重操作。

javaCopy Code
List<String> items = Arrays.asList("apple", "banana", "orange", "banana", "apple"); List<String> distinctSortedItems = items.stream() .distinct() .sorted() .collect(Collectors.toList()); System.out.println(distinctSortedItems); // 输出: [apple, banana, orange]

5. 并行流

Java Stream 还支持并行处理,通过 parallelStream() 方法可以轻松实现。

javaCopy Code
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.parallelStream() .reduce(0, Integer::sum); System.out.println("Parallel Sum: " + sum); // 输出: Parallel Sum: 15

6. 性能考量

虽然 Stream API 提供了强大的功能,但在某些情况下,使用传统的循环可能会更高效。因此,在使用 Stream 时,要结合具体场景来评估性能。

结论

Java Stream API 为数据处理提供了一种简洁而强大的方式,使得开发者能够以声明性的风格处理集合数据。通过丰富的操作符,Stream API 不仅提高了代码的可读性,也提升了处理效率。在实际应用中,合理使用 Stream API 可以显著减少代码的复杂度和行数。

希望本文能够帮助你更好地理解和使用 Java Stream 流,使你的编程工作更加高效和愉快!