跳转到内容

Java Stream过滤

来自代码酷

Java Stream过滤[编辑 | 编辑源代码]

Java Stream过滤是Java 8引入的Stream API中的核心操作之一,允许开发者通过条件筛选集合中的元素。它使用函数式编程风格,提供了一种声明式、高效的方式来处理数据集合。本教程将详细介绍`filter()`方法的使用,包括基础语法、常见用例和实际应用场景。

简介[编辑 | 编辑源代码]

在Java中,`Stream.filter()`是一个中间操作(intermediate operation),它接收一个谓词(Predicate)作为参数,并返回一个新的Stream,其中仅包含满足条件的元素。过滤操作不会修改原始数据源,而是创建一个新的视图。

基本语法:

Stream<T> filter(Predicate<? super T> predicate)

其中:

  • `Predicate`是一个函数式接口,接受一个参数并返回布尔值。
  • 如果元素满足条件(即Predicate返回`true`),则该元素会被保留在结果Stream中。

基础示例[编辑 | 编辑源代码]

示例1:过滤数字[编辑 | 编辑源代码]

以下代码演示如何从一个整数列表中过滤出所有偶数:

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

public class FilterExample {
    public static void main(String[] args) {
        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]
    }
}

输出:

[2, 4, 6, 8, 10]

示例2:过滤字符串[编辑 | 编辑源代码]

过滤长度大于3的字符串:

List<String> words = Arrays.asList("Java", "Stream", "API", "Filter", "Example");
List<String> longWords = words.stream()
    .filter(s -> s.length() > 3)
    .collect(Collectors.toList());

System.out.println(longWords);  // 输出: [Stream, Filter, Example]

高级用法[编辑 | 编辑源代码]

组合多个条件[编辑 | 编辑源代码]

通过逻辑运算符组合多个Predicate:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result = numbers.stream()
    .filter(n -> n > 5 && n < 9)  // 大于5且小于9
    .collect(Collectors.toList());

System.out.println(result);  // 输出: [6, 7, 8]

使用方法引用[编辑 | 编辑源代码]

当过滤逻辑较复杂时,可提取为独立方法并通过方法引用调用:

public class AdvancedFilter {
    public static boolean isPrime(int number) {
        if (number <= 1) return false;
        for (int i = 2; i <= Math.sqrt(number); i++) {
            if (number % i == 0) return false;
        }
        return true;
    }

    public static void main(String[] args) {
        List<Integer> primes = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).stream()
            .filter(AdvancedFilter::isPrime)  // 方法引用
            .collect(Collectors.toList());

        System.out.println(primes);  // 输出: [2, 3, 5, 7]
    }
}

实际应用场景[编辑 | 编辑源代码]

场景1:电商商品过滤[编辑 | 编辑源代码]

假设有一个商品列表,需要筛选出价格低于100且库存充足的商品:

class Product {
    String name;
    double price;
    int stock;

    // 构造方法、getter/setter省略
}

List<Product> products = Arrays.asList(
    new Product("Laptop", 999.99, 5),
    new Product("Mouse", 25.50, 10),
    new Product("Keyboard", 45.00, 0)
);

List<Product> availableCheapProducts = products.stream()
    .filter(p -> p.getPrice() < 100 && p.getStock() > 0)
    .collect(Collectors.toList());

// 输出: [Product{name='Mouse', price=25.5, stock=10}]

场景2:日志级别过滤[编辑 | 编辑源代码]

从日志列表中过滤出所有ERROR级别的记录:

enum LogLevel { INFO, WARN, ERROR, DEBUG }

class LogEntry {
    LogLevel level;
    String message;
    // 构造方法、getter/setter省略
}

List<LogEntry> logs = Arrays.asList(
    new LogEntry(LogLevel.INFO, "System started"),
    new LogEntry(LogLevel.ERROR, "Disk full"),
    new LogEntry(LogLevel.DEBUG, "Variable x=10")
);

List<LogEntry> errors = logs.stream()
    .filter(log -> log.getLevel() == LogLevel.ERROR)
    .collect(Collectors.toList());

// 输出: [LogEntry{level=ERROR, message='Disk full'}]

性能考虑[编辑 | 编辑源代码]

1. 惰性求值:过滤操作是惰性的,只有在终端操作(如`collect()`)调用时才会执行。 2. 短路操作:结合`findFirst()`等短路操作可以提高性能。 3. 顺序与并行:对于大数据集,可考虑使用`parallelStream()`。

可视化流程[编辑 | 编辑源代码]

flowchart LR A[原始集合] --> B[创建Stream] B --> C[filter操作] C --> D[满足条件?] D -->|是| E[保留元素] D -->|否| F[丢弃元素] E --> G[结果Stream]

数学表达[编辑 | 编辑源代码]

过滤操作可以形式化表示为: filter(S,P)={xSP(x)} 其中:

  • S是输入集合
  • P是谓词函数

常见问题[编辑 | 编辑源代码]

Q: filter()与removeIf()有何区别?

  • `filter()`创建一个新Stream,不修改原集合
  • `removeIf()`直接修改原集合(需在Collection上调用)

Q: 如何实现多条件复杂过滤?

  • 方案1:使用`&&`、`||`组合条件
  • 方案2:链式调用多个`filter()`
  • 方案3:定义复合Predicate(如`Predicate.and()`)

总结[编辑 | 编辑源代码]

Java Stream过滤提供了一种高效、声明式的方式来处理集合数据。关键点:

  • 使用`filter(Predicate)`进行条件筛选
  • 支持方法引用和lambda表达式
  • 可与其它Stream操作(如`map`、`sorted`)组合使用
  • 适合处理大数据集的筛选需求

通过合理使用过滤操作,可以显著提高代码的可读性和维护性,同时利用Stream的惰性求值特性优化性能。