Java Stream筛选案例怎么过滤数据

wen java案例 22

本文目录导读:

Java Stream筛选案例怎么过滤数据

  1. 基础案例:筛选年龄大于18的用户
  2. 多条件筛选:名字以A开头 且 年龄大于18
  3. 排除/取反:筛选未成年(年龄 < 18)
  4. 去重后筛选:结合 distinct()
  5. 复杂对象属性筛选
  6. ⚠️ 几个容易被忽略的细节(面试常问)

Java Stream 的 filter() 方法是用来筛选数据最核心的工具,它接收一个 Predicate(断言函数,即返回 boolean 的 Lambda 表达式),保留满足条件的元素。

下面为你提供 5 个从简单到复杂的实战案例,覆盖最常见的筛选场景。

基础案例:筛选年龄大于18的用户

场景:从一个用户列表中找出成年人。

import java.util.List;
import java.util.stream.Collectors;
public class StreamFilterExample {
    public static void main(String[] args) {
        // 准备数据
        List<User> users = List.of(
            new User("Alice", 25),
            new User("Bob", 17),
            new User("Charlie", 19),
            new User("David", 16)
        );
        // 筛选年龄 >= 18 的用户
        List<User> adults = users.stream()
            .filter(user -> user.getAge() >= 18)  // 关键:条件表达式
            .collect(Collectors.toList());
        System.out.println(adults);
        // 输出:[User(name=Alice, age=25), User(name=Charlie, age=19)]
    }
}
// 辅助类
class User {
    private String name;
    private int age;
    // 构造方法、getter、toString 略(需要自己补全)
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public int getAge() { return age; }
    public String getName() { return name; }
    @Override
    public String toString() {
        return "User(name=" + name + ", age=" + age + ")";
    }
}

关键点

  • filter() 内部是 Lambda:user -> user.getAge() >= 18
  • 返回 true 的保留,false 的丢弃。

多条件筛选:名字以A开头 且 年龄大于18

场景:筛选名字以 "A" 开头且成年的人。

List<User> result = users.stream()
    .filter(user -> user.getName().startsWith("A") && user.getAge() >= 18)
    .collect(Collectors.toList());
// 结果:[User(name=Alice, age=25)]

也可以分步写(更清晰)

Predicate<User> nameStartsWithA = user -> user.getName().startsWith("A");
Predicate<User> ageAdult = user -> user.getAge() >= 18;
List<User> result = users.stream()
    .filter(nameStartsWithA.and(ageAdult))  // 使用 Predicate 的 and()
    .collect(Collectors.toList());

排除/取反:筛选未成年(年龄 < 18)

场景:找出年龄小于 18 的用户。

直接写条件

List<User> minors = users.stream()
    .filter(user -> user.getAge() < 18)
    .collect(Collectors.toList());
// 结果:[User(name=Bob, age=17), User(name=David, age=16)]

使用 Predicate.negate()(取反)

Predicate<User> isAdult = user -> user.getAge() >= 18;
List<User> minors = users.stream()
    .filter(isAdult.negate())  // 取反,相当于 !isAdult
    .collect(Collectors.toList());

去重后筛选:结合 distinct()

场景:有一个包含重复元素的列表,筛选出偶数并去重。

List<Integer> numbers = List.of(1, 2, 2, 3, 4, 4, 5, 6);
List<Integer> evenDistinct = numbers.stream()
    .filter(n -> n % 2 == 0)      // 筛选偶数
    .distinct()                   // 去重
    .collect(Collectors.toList());
System.out.println(evenDistinct); // 输出:[2, 4, 6]

复杂对象属性筛选

场景:有一个订单列表 Order,每个订单包含 amount(金额)和 status(状态)。
需求:找出状态为 “PAID” 且金额大于 100 的订单。

List<Order> orders = List.of(
    new Order("001", 150.0, "PAID"),
    new Order("002", 50.0, "PAID"),
    new Order("003", 200.0, "UNPAID")
);
List<Order> paidHighValue = orders.stream()
    .filter(order -> "PAID".equals(order.getStatus()) && order.getAmount() > 100)
    .collect(Collectors.toList());
System.out.println(paidHighValue);
// 输出:[Order(id=001, amount=150.0, status=PAID)]

⚠️ 几个容易被忽略的细节(面试常问)

  1. filter() 不会修改原数据

    users.stream().filter(u -> u.getAge() > 18).collect(...);
    // users 列表本身不变,这是函数式编程的特点(无副作用)
  2. 顺序问题filter() 放在前面可以减少后续操作的数据量,提升性能。

    // 推荐:先过滤,再 map
    list.stream()
        .filter(...)    // 先减少数据
        .map(...)       // 再处理少量数据
  3. 空指针风险User::getName 可能为 null,直接调用 startsWith() 会报 NullPointerException

    // 安全写法
    .filter(user -> user.getName() != null && user.getName().startsWith("A"))
    // 或者使用 Objects::nonNull
    .filter(user -> Objects.nonNull(user.getName()) && user.getName().startsWith("A"))
场景 写法
单条件 filter(x -> x > 5)
多条件 AND filter(x -> x > 5 && x < 10)
多条件 OR filter(x -> x > 5 \|\| x < 0)
取反 filter(Predicate.not(x -> x > 5))filter(x -> !(x > 5))
配合 distinct filter(...).distinct()
配合 limit filter(...).limit(5) (只要前5个满足条件的)

如果你有具体的业务场景(比如筛选日期范围、模糊匹配字符串等),可以告诉我,我可以帮你写出对应的案例。

抱歉,评论功能暂时关闭!