集合处理利器,Java中的Stream流API

前言

在Java 8之前,处理集合数据通常需要写大量的样板代码。比如过滤、映射、聚合等操作,都需要手动编写循环和条件判断。这种方式不仅冗长,而且容易出错。Stream API的引入,就是为了简化这些操作,提供一种声明式的、函数式编程风格的数据处理方式。

什么是Stream?

Stream不是数据结构,它是一个数据处理管道 。你可以把它想象成一个工厂的流水线,原材料(数据源)进入流水线,经过各种工序(中间操作),最终产出成品(终端操作结果)。关键点是:Stream本身不存储数据,它只是对数据源进行操作

我们先来看一个对比:

java 复制代码
// Java 8 之前的写法
List<String> names = new ArrayList<>();
for (Person person : persons) {
    if (person.getAge() > 18) {
        names.add(person.getName().toUpperCase());
    }
}

// Stream API 写法
List<String> names = persons.stream()
    .filter(person -> person.getAge() > 18)
    .map(Person::getName)
    .map(String::toUpperCase)
    .collect(Collectors.toList());

可以看到,Stream API的代码更加简洁、易读,而且更接近自然语言的表达方式。

Stream的三个核心概念

  1. 数据源:可以是集合、数组等''
  2. 中间操作:返回一个新的Stream,可以链式调用
  3. 终端操作:产生结果或副作用,结束Stream的处理
graph LR A[数据源: List/Array] --> B[中间操作: filter/map/sorted] B --> C[中间操作: map/flatMap/distinct] C --> D[终端操作: collect/forEach/count] D --> E[结果: List/void/long]

一、核心接口详解

1.1 Stream接口继承关系

classDiagram BaseStream <|-- Stream BaseStream <|-- IntStream BaseStream <|-- LongStream BaseStream <|-- DoubleStream Stream <|-- IntStream Stream <|-- LongStream Stream <|-- DoubleStream
java 复制代码
// BaseStream接口定义了基本的流操作
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {
    // 关闭流(用于并行流)
    void close();
    boolean isParallel();
    S sequential();
    S parallel();
    S unordered();
    S onClose(Runnable closeHandler);
}

// Stream接口继承BaseStream,添加了具体的流操作
public interface Stream<T> extends BaseStream<T, Stream<T>> {
    // 中间操作
    Stream<T> filter(Predicate<? super T> predicate);
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    Stream<T> distinct();
    Stream<T> sorted();
    Stream<T> sorted(Comparator<? super T> comparator);
    Stream<T> peek(Consumer<? super T> action);
    Stream<T> limit(long maxSize);
    Stream<T> skip(long n);
    
    // 终端操作
    void forEach(Consumer<? super T> action);
    void forEachOrdered(Consumer<? super T> action);
    Object[] toArray();
    <A> A[] toArray(IntFunction<A[]> generator);
    T reduce(T identity, BinaryOperator<T> accumulator);
    Optional<T> reduce(BinaryOperator<T> accumulator);
    <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
    <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
    <R, A> R collect(Collector<? super T, A, R> collector);
    Optional<T> min(Comparator<? super T> comparator);
    Optional<T> max(Comparator<? super T> comparator);
    long count();
    boolean anyMatch(Predicate<? super T> predicate);
    boolean allMatch(Predicate<? super T> predicate);
    boolean noneMatch(Predicate<? super T> predicate);
    Optional<T> findFirst();
    Optional<T> findAny();
}

二、中间操作详解

中间操作是Stream API的核心,它们都是惰性求值的,只有在终端操作执行时才会真正执行。

2.1 filter - 过滤

java 复制代码
// 理论:根据Predicate条件过滤元素
// 源码:Stream<T> filter(Predicate<? super T> predicate);

@Test
public void testFilter() {
    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)
        .collect(Collectors.toList());
    
    System.out.println("偶数: " + evenNumbers); // [2, 4, 6, 8, 10]
    
    // 案例:过滤有效用户
    List<User> users = Arrays.asList(
        new User("Alice", 25, true),
        new User("Bob", 17, false),
        new User("Charlie", 30, true)
    );
    
    List<User> activeAdultUsers = users.stream()
        .filter(user -> user.isActive() && user.getAge() >= 18)
        .collect(Collectors.toList());
    
    System.out.println("活跃成年用户数: " + activeAdultUsers.size());
}

static class User {
    private String name;
    private int age;
    private boolean active;
    
    public User(String name, int age, boolean active) {
        this.name = name;
        this.age = age;
        this.active = active;
    }
    
    // getters...
    public String getName() { return name; }
    public int getAge() { return age; }
    public boolean isActive() { return active; }
}

2.2 map - 映射

java 复制代码
// 理论:将每个元素转换为另一个元素
// 源码:<R> Stream<R> map(Function<? super T, ? extends R> mapper);

@Test
public void testMap() {
    List<String> names = Arrays.asList("alice", "bob", "charlie");
    
    // 转换为大写
    List<String> upperNames = names.stream()
        .map(String::toUpperCase)
        .collect(Collectors.toList());
    
    System.out.println("大写名字: " + upperNames); // [ALICE, BOB, CHARLIE]
    
    // 案例:提取用户ID
    List<User> users = Arrays.asList(
        new User("Alice", 25, true),
        new User("Bob", 17, false),
        new User("Charlie", 30, true)
    );
    
    List<String> userIds = users.stream()
        .map(user -> "user_" + user.getName().toLowerCase())
        .collect(Collectors.toList());
    
    System.out.println("用户ID: " + userIds);
    
    // 复杂映射:计算年龄平方
    List<Integer> ageSquares = users.stream()
        .map(user -> user.getAge() * user.getAge())
        .collect(Collectors.toList());
    
    System.out.println("年龄平方: " + ageSquares);
}

2.3 flatMap - 扁平化映射

java 复制代码
// 理论:将多个Stream合并为一个Stream
// 源码:<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

@Test
public void testFlatMap() {
    // 场景:处理嵌套集合
    List<List<String>> nestedList = Arrays.asList(
        Arrays.asList("a", "b"),
        Arrays.asList("c", "d", "e"),
        Arrays.asList("f")
    );
    
    // 扁平化处理
    List<String> flatList = nestedList.stream()
        .flatMap(Collection::stream)
        .collect(Collectors.toList());
    
    System.out.println("扁平化结果: " + flatList); // [a, b, c, d, e, f]
    
    // 案例:提取订单中的所有商品
    List<Order> orders = Arrays.asList(
        new Order(Arrays.asList("商品1", "商品2")),
        new Order(Arrays.asList("商品3")),
        new Order(Arrays.asList("商品4", "商品5", "商品6"))
    );
    
    List<String> allProducts = orders.stream()
        .flatMap(order -> order.getProducts().stream())
        .collect(Collectors.toList());
    
    System.out.println("所有商品: " + allProducts);
}

static class Order {
    private List<String> products;
    
    public Order(List<String> products) {
        this.products = products;
    }
    
    public List<String> getProducts() {
        return products;
    }
}

2.4 distinct - 去重

java 复制代码
// 理论:根据equals和hashCode去重
// 源码:Stream<T> distinct();

@Test
public void testDistinct() {
    List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 5, 5);
    
    List<Integer> distinctNumbers = numbers.stream()
        .distinct()
        .collect(Collectors.toList());
    
    System.out.println("去重后: " + distinctNumbers); // [1, 2, 3, 4, 5]
    
    // 案例:获取唯一的用户城市
    List<User> users = Arrays.asList(
        new User("Alice", 25, true, "北京"),
        new User("Bob", 17, false, "上海"),
        new User("Charlie", 30, true, "北京"),
        new User("David", 22, true, "广州")
    );
    
    List<String> uniqueCities = users.stream()
        .map(User::getCity)
        .distinct()
        .collect(Collectors.toList());
    
    System.out.println("唯一城市: " + uniqueCities); // [北京, 上海, 广州]
}

static class User {
    private String name;
    private int age;
    private boolean active;
    private String city;
    
    public User(String name, int age, boolean active, String city) {
        this.name = name;
        this.age = age;
        this.active = active;
        this.city = city;
    }
    
    // getters...
    public String getName() { return name; }
    public int getAge() { return age; }
    public boolean isActive() { return active; }
    public String getCity() { return city; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(name, user.name) && Objects.equals(city, user.city);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, city);
    }
}

2.5 sorted - 排序

java 复制代码
// 理论:对流元素进行排序
// 源码:
// Stream<T> sorted();
// Stream<T> sorted(Comparator<? super T> comparator);

@Test
public void testSorted() {
    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3);
    
    // 自然排序
    List<Integer> sortedNumbers = numbers.stream()
        .sorted()
        .collect(Collectors.toList());
    
    System.out.println("自然排序: " + sortedNumbers); // [1, 2, 3, 5, 8, 9]
    
    // 自定义排序
    List<Integer> reverseSorted = numbers.stream()
        .sorted(Comparator.reverseOrder())
        .collect(Collectors.toList());
    
    System.out.println("逆序排序: " + reverseSorted);
    
    // 案例:按用户年龄排序
    List<User> users = Arrays.asList(
        new User("Alice", 25, true),
        new User("Bob", 17, false),
        new User("Charlie", 30, true)
    );
    
    List<User> sortedUsers = users.stream()
        .sorted(Comparator.comparing(User::getAge))
        .collect(Collectors.toList());
    
    System.out.println("按年龄排序: " + sortedUsers.stream()
        .map(user -> user.getName() + "(" + user.getAge() + ")")
        .collect(Collectors.toList()));
    
    // 多字段排序
    List<User> multiSortedUsers = users.stream()
        .sorted(Comparator.comparing(User::isActive, Comparator.reverseOrder())
                .thenComparing(User::getAge))
        .collect(Collectors.toList());
    
    System.out.println("按活跃状态和年龄排序: " + multiSortedUsers);
}

static class User {
    private String name;
    private int age;
    private boolean active;
    
    public User(String name, int age, boolean active) {
        this.name = name;
        this.age = age;
        this.active = active;
    }
    
    // getters...
    public String getName() { return name; }
    public int getAge() { return age; }
    public boolean isActive() { return active; }
}

2.6 peek - 调试操作

java 复制代码
// 理论:对每个元素执行操作,主要用于调试
// 源码:Stream<T> peek(Consumer<? super T> action);

@Test
public void testPeek() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    
    List<Integer> result = numbers.stream()
        .peek(n -> System.out.println("处理前: " + n))
        .filter(n -> n % 2 == 0)
        .peek(n -> System.out.println("过滤后: " + n))
        .map(n -> n * n)
        .peek(n -> System.out.println("映射后: " + n))
        .collect(Collectors.toList());
    
    System.out.println("最终结果: " + result);
    
    // 案例:日志记录
    List<User> users = Arrays.asList(
        new User("Alice", 25, true),
        new User("Bob", 17, false),
        new User("Charlie", 30, true)
    );
    
    List<User> processedUsers = users.stream()
        .peek(user -> log.info("开始处理用户: " + user.getName()))
        .filter(user -> user.getAge() >= 18)
        .peek(user -> log.info("用户符合年龄要求: " + user.getName()))
        .map(user -> {
            user.setActive(true);
            return user;
        })
        .peek(user -> log.info("用户已激活: " + user.getName()))
        .collect(Collectors.toList());
}

2.7 limit & skip - 限制和跳过

java 复制代码
// 理论:limit限制元素数量,skip跳过元素数量
// 源码:
// Stream<T> limit(long maxSize);
// Stream<T> skip(long n);

@Test
public void testLimitSkip() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    
    // 限制前5个元素
    List<Integer> firstFive = numbers.stream()
        .limit(5)
        .collect(Collectors.toList());
    
    System.out.println("前5个: " + firstFive); // [1, 2, 3, 4, 5]
    
    // 跳过前3个元素
    List<Integer> skipThree = numbers.stream()
        .skip(3)
        .collect(Collectors.toList());
    
    System.out.println("跳过前3个: " + skipThree); // [4, 5, 6, 7, 8, 9, 10]
    
    // 分页处理
    int pageSize = 3;
    int pageNum = 2;
    
    List<Integer> pageData = numbers.stream()
        .skip((long) (pageNum - 1) * pageSize)
        .limit(pageSize)
        .collect(Collectors.toList());
    
    System.out.println("第2页数据: " + pageData); // [4, 5, 6]
    
    // 案例:获取热门商品前10名
    List<Product> products = generateProducts(100); // 假设生成100个商品
    
    List<Product> top10Products = products.stream()
        .sorted(Comparator.comparing(Product::getSales).reversed())
        .limit(10)
        .collect(Collectors.toList());
    
    System.out.println("热门商品前10名数量: " + top10Products.size());
}

static class Product {
    private String name;
    private int sales;
    
    public Product(String name, int sales) {
        this.name = name;
        this.sales = sales;
    }
    
    // getters...
    public String getName() { return name; }
    public int getSales() { return sales; }
}

private List<Product> generateProducts(int count) {
    List<Product> products = new ArrayList<>();
    Random random = new Random();
    for (int i = 0; i < count; i++) {
        products.add(new Product("商品" + i, random.nextInt(1000)));
    }
    return products;
}

三、终端操作详解

终端操作是Stream的终点,它们会触发整个流水线的执行。

3.1 forEach - 遍历

java 复制代码
// 理论:对每个元素执行操作
// 源码:void forEach(Consumer<? super T> action);

@Test
public void testForEach() {
    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    
    // 串行处理
    names.stream()
        .forEach(name -> System.out.println("Hello, " + name));
    
    // 并行处理(注意顺序不保证)
    names.parallelStream()
        .forEach(name -> System.out.println("Parallel: " + name));
    
    // 保证顺序的并行处理
    names.parallelStream()
        .forEachOrdered(name -> System.out.println("Ordered: " + name));
    
    // 案例:批量发送邮件
    List<User> users = Arrays.asList(
        new User("Alice", "alice@example.com"),
        new User("Bob", "bob@example.com"),
        new User("Charlie", "charlie@example.com")
    );
    
    users.stream()
        .filter(User::isActive)
        .forEach(user -> {
            // 模拟发送邮件
            System.out.println("发送邮件给: " + user.getEmail());
            // emailService.send(user.getEmail(), "欢迎使用我们的服务");
        });
}

static class User {
    private String name;
    private String email;
    private boolean active = true;
    
    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }
    
    // getters...
    public String getName() { return name; }
    public String getEmail() { return email; }
    public boolean isActive() { return active; }
    public void setActive(boolean active) { this.active = active; }
}

3.2 collect - 收集

java 复制代码
// 理论:将流元素收集到集合中
// 源码:<R, A> R collect(Collector<? super T, A, R> collector);

@Test
public void testCollect() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    
    // 收集到List
    List<Integer> evenList = numbers.stream()
        .filter(n -> n % 2 == 0)
        .collect(Collectors.toList());
    
    // 收集到Set
    Set<Integer> evenSet = numbers.stream()
        .filter(n -> n % 2 == 0)
        .collect(Collectors.toSet());
    
    // 收集到Map
    Map<String, Integer> numberMap = numbers.stream()
        .collect(Collectors.toMap(
            n -> "number_" + n,  // key mapper
            n -> n               // value mapper
        ));
    
    System.out.println("Map: " + numberMap);
    
    // 分组收集
    Map<Boolean, List<Integer>> partitioned = numbers.stream()
        .collect(Collectors.partitioningBy(n -> n % 2 == 0));
    
    System.out.println("偶数分组: " + partitioned.get(true));
    System.out.println("奇数分组: " + partitioned.get(false));
    
    // 案例:按部门分组用户
    List<User> users = Arrays.asList(
        new User("Alice", "IT"),
        new User("Bob", "HR"),
        new User("Charlie", "IT"),
        new User("David", "Finance")
    );
    
    Map<String, List<User>> usersByDepartment = users.stream()
        .collect(Collectors.groupingBy(User::getDepartment));
    
    System.out.println("按部门分组:");
    usersByDepartment.forEach((dept, userList) -> {
        System.out.println(dept + ": " + userList.stream()
            .map(User::getName)
            .collect(Collectors.toList()));
    });
    
    // 统计收集
    IntSummaryStatistics stats = numbers.stream()
        .collect(Collectors.summarizingInt(Integer::intValue));
    
    System.out.println("统计信息: " + stats);
}

static class User {
    private String name;
    private String department;
    
    public User(String name, String department) {
        this.name = name;
        this.department = department;
    }
    
    // getters...
    public String getName() { return name; }
    public String getDepartment() { return department; }
}

3.3 reduce - 归约

java 复制代码
// 理论:将流元素归约为单个值
// 源码:
// T reduce(T identity, BinaryOperator<T> accumulator);
// Optional<T> reduce(BinaryOperator<T> accumulator);

@Test
public void testReduce() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    
    // 求和
    int sum = numbers.stream()
        .reduce(0, Integer::sum);
    
    System.out.println("求和: " + sum); // 15
    
    // 求积
    int product = numbers.stream()
        .reduce(1, (a, b) -> a * b);
    
    System.out.println("求积: " + product); // 120
    
    // 找最大值
    Optional<Integer> max = numbers.stream()
        .reduce(Integer::max);
    
    System.out.println("最大值: " + max.orElse(0)); // 5
    
    // 字符串连接
    List<String> words = Arrays.asList("Hello", "World", "Java");
    
    String sentence = words.stream()
        .reduce("", (a, b) -> a + " " + b)
        .trim();
    
    System.out.println("句子: " + sentence); // Hello World Java
    
    // 案例:计算订单总金额
    List<Order> orders = Arrays.asList(
        new Order(100.0),
        new Order(200.5),
        new Order(50.25)
    );
    
    double totalAmount = orders.stream()
        .map(Order::getAmount)
        .reduce(0.0, Double::sum);
    
    System.out.println("订单总金额: " + totalAmount);
    
    // 案例:合并用户权限
    List<User> users = Arrays.asList(
        new User("Alice", Arrays.asList("read", "write")),
        new User("Bob", Arrays.asList("read", "delete")),
        new User("Charlie", Arrays.asList("write", "execute"))
    );
    
    Set<String> allPermissions = users.stream()
        .map(User::getPermissions)
        .flatMap(List::stream)
        .collect(Collectors.toSet());
    
    System.out.println("所有权限: " + allPermissions);
}

static class Order {
    private double amount;
    
    public Order(double amount) {
        this.amount = amount;
    }
    
    public double getAmount() { return amount; }
}

static class User {
    private String name;
    private List<String> permissions;
    
    public User(String name, List<String> permissions) {
        this.name = name;
        this.permissions = permissions;
    }
    
    public List<String> getPermissions() { return permissions; }
}

3.4 match操作 - 匹配检查

java 复制代码
// 理论:检查元素是否满足条件
// 源码:
// boolean anyMatch(Predicate<? super T> predicate);
// boolean allMatch(Predicate<? super T> predicate);
// boolean noneMatch(Predicate<? super T> predicate);

@Test
public void testMatch() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    
    // 是否存在偶数
    boolean hasEven = numbers.stream()
        .anyMatch(n -> n % 2 == 0);
    
    System.out.println("存在偶数: " + hasEven); // true
    
    // 是否全是偶数
    boolean allEven = numbers.stream()
        .allMatch(n -> n % 2 == 0);
    
    System.out.println("全是偶数: " + allEven); // false
    
    // 是否没有负数
    boolean noNegative = numbers.stream()
        .noneMatch(n -> n < 0);
    
    System.out.println("没有负数: " + noNegative); // true
    
    // 案例:验证用户权限
    List<User> users = Arrays.asList(
        new User("Alice", true, true),
        new User("Bob", true, false),
        new User("Charlie", false, true)
    );
    
    // 检查是否有活跃用户
    boolean hasActiveUser = users.stream()
        .anyMatch(User::isActive);
    
    System.out.println("有活跃用户: " + hasActiveUser);
    
    // 检查是否所有用户都已验证
    boolean allVerified = users.stream()
        .allMatch(User::isVerified);
    
    System.out.println("所有用户已验证: " + allVerified);
    
    // 检查是否没有被封禁用户
    boolean noBannedUser = users.stream()
        .noneMatch(User::isBanned);
    
    System.out.println("没有被封禁用户: " + noBannedUser);
}

static class User {
    private String name;
    private boolean active;
    private boolean verified;
    private boolean banned = false;
    
    public User(String name, boolean active, boolean verified) {
        this.name = name;
        this.active = active;
        this.verified = verified;
    }
    
    public User(String name, boolean active, boolean verified, boolean banned) {
        this.name = name;
        this.active = active;
        this.verified = verified;
        this.banned = banned;
    }
    
    // getters...
    public boolean isActive() { return active; }
    public boolean isVerified() { return verified; }
    public boolean isBanned() { return banned; }
}

3.5 find操作 - 查找

java 复制代码
// 理论:查找元素
// 源码:
// Optional<T> findFirst();
// Optional<T> findAny();

@Test
public void testFind() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    
    // 查找第一个元素
    Optional<Integer> first = numbers.stream()
        .findFirst();
    
    System.out.println("第一个元素: " + first.orElse(0)); // 1
    
    // 查找任意偶数
    Optional<Integer> anyEven = numbers.stream()
        .filter(n -> n % 2 == 0)
        .findAny();
    
    System.out.println("任意偶数: " + anyEven.orElse(0));
    
    // 案例:查找特定用户
    List<User> users = Arrays.asList(
        new User("Alice", 25),
        new User("Bob", 17),
        new User("Charlie", 30)
    );
    
    // 查找第一个成年用户
    Optional<User> firstAdult = users.stream()
        .filter(user -> user.getAge() >= 18)
        .findFirst();
    
    if (firstAdult.isPresent()) {
        System.out.println("第一个成年用户: " + firstAdult.get().getName());
    }
    
    // 在并行流中查找
    Optional<User> anyAdult = users.parallelStream()
        .filter(user -> user.getAge() >= 18)
        .findAny();
    
    System.out.println("任意成年用户: " + anyAdult.map(User::getName).orElse("无"));
}

static class User {
    private String name;
    private int age;
    
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // getters...
    public String getName() { return name; }
    public int getAge() { return age; }
}

四、高级用法

4.1 并行流

并行流是Stream API的一个重要特性,它可以在多核CPU上并行处理数据,提高性能。

java 复制代码
@Test
public void testParallelStream() {
    List<Integer> numbers = IntStream.range(1, 1000000)
        .boxed()
        .collect(Collectors.toList());
    
    // 串行处理
    long startTime = System.currentTimeMillis();
    long sum1 = numbers.stream()
        .mapToLong(n -> n * n)
        .sum();
    long serialTime = System.currentTimeMillis() - startTime;
    
    // 并行处理
    startTime = System.currentTimeMillis();
    long sum2 = numbers.parallelStream()
        .mapToLong(n -> n * n)
        .sum();
    long parallelTime = System.currentTimeMillis() - startTime;
    
    System.out.println("串行结果: " + sum1 + ", 耗时: " + serialTime + "ms");
    System.out.println("并行结果: " + sum2 + ", 耗时: " + parallelTime + "ms");
    System.out.println("加速比: " + (double) serialTime / parallelTime);
    
    // 案例:大数据处理
    List<DataRecord> records = generateLargeDataset(1000000);
    
    // 并行处理数据转换
    List<ProcessedRecord> processedRecords = records.parallelStream()
        .map(this::processRecord)
        .filter(Objects::nonNull)
        .collect(Collectors.toList());
    
    System.out.println("处理记录数: " + processedRecords.size());
}

private DataRecord processRecord(DataRecord record) {
    // 模拟耗时操作
    try {
        Thread.sleep(1);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        return null;
    }
    return new ProcessedRecord(record.getId(), record.getValue() * 2);
}

private List<DataRecord> generateLargeDataset(int size) {
    return IntStream.range(0, size)
        .mapToObj(i -> new DataRecord(i, Math.random()))
        .collect(Collectors.toList());
}

static class DataRecord {
    private int id;
    private double value;
    
    public DataRecord(int id, double value) {
        this.id = id;
        this.value = value;
    }
    
    // getters...
    public int getId() { return id; }
    public double getValue() { return value; }
}

static class ProcessedRecord {
    private int id;
    private double processedValue;
    
    public ProcessedRecord(int id, double processedValue) {
        this.id = id;
        this.processedValue = processedValue;
    }
    
    // getters...
    public int getId() { return id; }
    public double getProcessedValue() { return processedValue; }
}

4.2 自定义Collector

在复杂的业务场景中,我们经常需要自定义Collector来满足特定的收集需求。

java 复制代码
@Test
public void testCustomCollector() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    
    // 自定义Collector:收集到不可变List
    List<Integer> immutableList = numbers.stream()
        .filter(n -> n % 2 == 0)
        .collect(Collector.of(
            ArrayList::new,           // supplier
            ArrayList::add,           // accumulator
            (list1, list2) -> {       // combiner
                list1.addAll(list2);
                return list1;
            },
            Collections::unmodifiableList  // finisher
        ));
    
    System.out.println("不可变列表: " + immutableList);
    
    // 自定义Collector:分组统计
    Map<Boolean, Long> countByEven = numbers.stream()
        .collect(Collector.of(
            () -> new HashMap<Boolean, Long>() {{
                put(true, 0L);
                put(false, 0L);
            }},
            (map, item) -> map.merge(item % 2 == 0, 1L, Long::sum),
            (map1, map2) -> {
                map2.forEach((key, value) -> map1.merge(key, value, Long::sum));
                return map1;
            }
        ));
    
    System.out.println("分组统计: " + countByEven);
    
    // 案例:自定义Collector用于业务统计
    List<Order> orders = Arrays.asList(
        new Order("Alice", 100.0, "Electronics"),
        new Order("Bob", 50.0, "Books"),
        new Order("Charlie", 200.0, "Electronics"),
        new Order("David", 30.0, "Books")
    );
    
    // 按类别统计订单
    Map<String, OrderStatistics> statsByCategory = orders.stream()
        .collect(Collectors.groupingBy(
            Order::getCategory,
            Collector.of(
                OrderStatistics::new,
                OrderStatistics::accept,
                OrderStatistics::combine,
                Collector.Characteristics.IDENTITY_FINISH
            )
        ));
    
    System.out.println("按类别统计:");
    statsByCategory.forEach((category, stats) -> {
        System.out.println(category + " - 数量: " + stats.getCount() + 
                          ", 总额: " + stats.getTotalAmount() + 
                          ", 平均值: " + stats.getAverageAmount());
    });
}

static class Order {
    private String customer;
    private double amount;
    private String category;
    
    public Order(String customer, double amount, String category) {
        this.customer = customer;
        this.amount = amount;
        this.category = category;
    }
    
    // getters...
    public String getCustomer() { return customer; }
    public double getAmount() { return amount; }
    public String getCategory() { return category; }
}

static class OrderStatistics {
    private long count = 0;
    private double totalAmount = 0.0;
    
    public void accept(Order order) {
        count++;
        totalAmount += order.getAmount();
    }
    
    public OrderStatistics combine(OrderStatistics other) {
        this.count += other.count;
        this.totalAmount += other.totalAmount;
        return this;
    }
    
    public double getAverageAmount() {
        return count == 0 ? 0 : totalAmount / count;
    }
    
    // getters...
    public long getCount() { return count; }
    public double getTotalAmount() { return totalAmount; }
}
相关推荐
Doris_20232 小时前
Python条件判断语句 if、elif 、else
前端·后端·python
玉衡子2 小时前
八、MySQL全局优化总结&MySQL8新特性
java·mysql
9号达人2 小时前
Java 14 新特性详解与实践
java·后端·面试
Doris_20232 小时前
Python 模式匹配match case
前端·后端·python
ytadpole2 小时前
揭秘XXL-JOB:Bean、GLUE 与脚本模式的底层奥秘
java·后端
计算机毕业设计木哥2 小时前
计算机毕设选题推荐:基于Java+SpringBoot物品租赁管理系统【源码+文档+调试】
java·vue.js·spring boot·mysql·spark·毕业设计·课程设计
青衫客362 小时前
Spring异步编程- 浅谈 Reactor 核心操作符
java·spring·响应式编程
shark_chili2 小时前
计算机磁盘的奥秘:从硬件构造到操作系统管理
后端
Seven972 小时前
剑指offer-30、连续⼦数组的最⼤和
java