跳至主要內容

05.Stream过滤

LiuSongLing大约 3 分钟javajavastream

Java 8 引入的Stream API彻底改变了集合数据处理方式,其中filter()方法凭借**高达83%**的开发使用率成为最常用的操作之一。

本文将深入剖析如何通过Lambda表达式高效使用filter()方法,并分享生产环境中的最佳实践。

1.filter() 方法基础

方法定义

Stream<T> filter(Predicate<? super T> predicate)
  • 功能:基于断言条件过滤流元素
  • 特性惰性求值(仅声明过滤逻辑,不立即执行)
  • 链式调用:可与其他Stream操作(如map/sorted)组合

基础示例

List<String> languages = Arrays.asList("Java""Python""""Kotlin""  ");

// 过滤非空字符串(包含空白字符串检查)
List<String> validLanguages = languages.stream()
        .filter(s -> s != null && !s.trim().isEmpty())
        .collect(Collectors.toList());

System.out.println(validLanguages); 
// 输出: [Java, Python, Kotlin]

2.多条件过滤策略

1.链式过滤(推荐)

List<Product> products = getProductsFromDB();

// 筛选价格>100且库存>0的商品
List<Product> availableExpensiveProducts = products.stream()
        .filter(p -> p.getPrice() > 100)
        .filter(p -> p.getStock() > 0)
        .collect(Collectors.toList());

2.复合条件表达式

// 找出18-25岁且姓"王"的用户
List<User> targetUsers = userList.stream()
        .filter(u -> u.getAge() >= 18 && 
                    u.getAge() <= 25 && 
                    u.getName().startsWith("王"))
        .collect(Collectors.toList());

3.Predicate组合技

Predicate<Employee> isDeveloper = e -> "开发部".equals(e.getDepartment());
Predicate<Employee> isSenior = e -> e.getLevel() >= 3;

// 组合条件:开发部且职级≥3
List<Employee> seniorDevs = employees.stream()
        .filter(isDeveloper.and(isSenior))
        .collect(Collectors.toList());

3.生产环境实战技巧

1.空值安全处理

List<String> dataWithNulls = Arrays.asList("apple"null"orange");

// 方案1:先过滤null再处理
List<String> validData = dataWithNulls.stream()
        .filter(Objects::nonNull)
        .filter(s -> s.length() > 3)
        .collect(Collectors.toList());

// 方案2:使用Optional包装
dataWithNulls.stream()
        .map(Optional::ofNullable)
        .filter(opt -> opt.map(s -> s.length() > 3).orElse(false))
        .map(Optional::get)
        .forEach(System.out::println);

2.性能优化要点

  • 短路操作优先:尽早过滤掉无效数据

    // 错误示范:先执行耗时操作再过滤
    .filter(s -> expensiveOperation(s) && s.length() > 5)
    
    // 正确做法:优先过滤简单条件
    .filter(s -> s.length() > 5)
    .filter(s -> expensiveOperation(s))
    
  • 并行流谨慎使用:数据量>10万时测试验证

    List<BigData> result = bigDataSet.parallelStream()
            .filter(b -> b.isValid()) // 确保线程安全
            .collect(Collectors.toList());
    

3.调试技巧

使用peek()观察过滤过程:

List<Integer> numbers = Arrays.asList(12345);

List<Integer> evenNumbers = numbers.stream()
        .peek(n -> System.out.println("原始值: " + n))
        .filter(n -> n % 2 == 0)
        .peek(n -> System.out.println("通过过滤: " + n))
        .collect(Collectors.toList());

4.与其他操作结合

1.与map()配合

// 提取符合条件的用户名
List<String> adminNames = userList.stream()
        .filter(u -> "管理员".equals(u.getRole()))
        .map(User::getName)
        .collect(Collectors.toList());

2.与findFirst()结合

// 查找第一个匹配元素
Optional<Order> urgentOrder = orderList.stream()
        .filter(o -> "紧急".equals(o.getPriority()))
        .findFirst();

3.统计过滤结果

long invalidCount = dataList.stream()
        .filter(d -> !d.validate())
        .count();

5.常见陷阱与解决方案

问题场景错误表现解决方案
修改外部变量Lambda内修改非final变量使用原子类如AtomicInteger
复杂业务逻辑filter内嵌多层条件判断封装为Predicate工具类
并行流线程安全过滤结果不一致确保Predicate无状态
自动装箱开销频繁int-Integer转换使用IntStream等原始流

总结

filter() + Lambda组合拳可实现:

声明式编程:代码更贴近业务描述
高效过滤:平均提升集合处理速度40%
灵活组合:与Stream API无缝衔接

开发建议: 1.优先使用java.util.function.Predicate 2.复杂条件建议拆分为多个filter操作 3.生产环境添加过滤日志监控