Java中使用stream流代替for循环

81 阅读2分钟

使用Stream API的好处

  • Stream提供了丰富的数据处理函数,如filtermapreducecollect等,这些函数可以轻松实现数据筛选、转换、汇总等操作。
  • 使用Stream,无需显式迭代集合,因为Stream API会在内部进行迭代,这使得代码更加简洁,也避免了因迭代导致的错误。

案例一

假设有一个商品列表,我们需要过滤出价格大于50的商品,并计算这些商品的总价格。

传统的for循环方式

List<Product> products = // 假设这是商品列表;
double total = 0;
for(Product product : products) {
    if(product.getPrice() > 50) {
        total += product.getPrice();
    }
}
System.out.println("Total: " + total);

使用Stream API的方式

List<Product> products = // 假设这是商品列表;
double total = products.stream()
                        .filter(product -> product.getPrice() > 50)
                        .mapToDouble(Product::getPrice)
                        .sum();
System.out.println("Total: " + total);

案例二

假设我们有一个用户列表,每个用户都有姓名、年龄和月收入,我们的目标是:

  1. 筛选出月收入超过5000的用户;
  2. 将筛选出的用户的年龄增加1岁;
  3. 计算这些用户年龄增加后的平均年龄;
  4. 将结果用户信息收集到一个新的列表中。
  • 首先,定义一个User类来表示用户:
public class User {
    private String name;
    private int age;
    private double salary;

    public User(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    // getters and setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public double getSalary() { return salary; }
    public void setSalary(double salary) { this.salary = salary; }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }
}

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        List<User> users = Arrays.asList(
                new User("Alice", 30, 7000),
                new User("Bob", 25, 4000),
                new User("Charlie", 32, 5000),
                new User("David", 20, 2000)
        );

        // 1. 筛选月收入超过5000的用户
        // 2. 将筛选出的用户的年龄增加1岁
        // 3. 计算这些用户年龄增加后的平均年龄
        // 4. 将结果用户信息收集到一个新的列表中
        List<User> filteredAndUpdatedUsers = users.stream()
                .filter(user -> user.getSalary() > 5000)
                .peek(user -> user.setAge(user.getAge() + 1)) // 使用peek进行中间操作,增加年龄
                .collect(Collectors.toList());

        double averageAge = filteredAndUpdatedUsers.stream()
                .mapToInt(User::getAge)
                .average()
                .orElse(0); // 如果没有符合条件的用户,返回0

        System.out.println("Filtered and Updated Users: " + filteredAndUpdatedUsers);
        System.out.println("Average Age: " + averageAge);
    }
}

这个例子中,首先使用filter筛选出月收入超过5000的用户,然后通过peek操作增加这些用户的年龄。peek是一个中间操作,用于对流中的每个元素执行操作而不是终结操作。接下来,使用collect将流收集到一个新的列表中。最后,通过一个新的流操作计算增加年龄后的用户的平均年龄,使用mapToIntUser对象映射为年龄的int值,然后调用average计算平均值。