java中,stream的filter和list的removeIf筛选速度比较

在 Java 里,Stream 的filter和 List 的removeIf筛选效率要依据具体情形来判断。

1. 操作本质有别

  • Stream 的 filter
    • 它是一种中间操作,不会立刻执行,而是把筛选条件记录下来。只有遇到终端操作时,才会开始处理元素。
    • 此操作不会对原集合进行修改,而是生成一个新的流。
  • List 的 removeIf
    • 这是一种终端操作,会立即对原集合进行修改,删除满足条件的元素。
    • 它直接在原集合上进行元素的删除操作。

2. 效率对比分情况

  • 单次筛选场景
    当你只需要对集合进行一次筛选时,removeIf的效率更高。这是因为它直接在原集合上进行操作,避免了创建新的流和中间集合。
  • 链式操作场景
    如果需要进行多次筛选或者其他中间操作,Stream 的filter会更高效。因为 Stream 采用延迟执行策略,能将多个操作进行优化合并,减少遍历次数。

3. 示例与性能测试

下面通过代码来直观感受两者的性能差异:

java

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

public class FilterVsRemoveIf {
    public static void main(String[] args) {
        // 创建一个包含大量元素的列表
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            list.add(i);
        }

        // 测试Stream的filter
        long startTime = System.currentTimeMillis();
        List<Integer> filteredList = list.stream()
                .filter(e -> e % 2 == 0)
                .collect(Collectors.toList());
        long endTime = System.currentTimeMillis();
        System.out.println("Stream filter耗时: " + (endTime - startTime) + "ms");

        // 重新创建相同的列表用于测试removeIf
        list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            list.add(i);
        }

        // 测试List的removeIf
        startTime = System.currentTimeMillis();
        list.removeIf(e -> e % 2 != 0);
        endTime = System.currentTimeMillis();
        System.out.println("List removeIf耗时: " + (endTime - startTime) + "ms");
    }
}

测试结果分析

  • Stream 的 filter:由于要创建流、中间集合以及进行终端操作,会带来一些额外的开销。
  • List 的 removeIf:直接在原集合上进行操作,无需创建新的集合,所以速度更快。

4. 如何选择

  • 选择 Stream 的 filter 的情况
    • 你不想对原集合进行修改。
    • 需要进行链式操作,比如多次筛选、映射等。
    • 希望代码更加简洁易读。
  • 选择 List 的 removeIf 的情况
    • 你想直接修改原集合。
    • 只需要进行一次筛选操作。
    • 追求更高的性能。

综上所述,在单次筛选且需要修改原集合时,removeIf是更好的选择;而在需要链式操作或者保留原集合的场景下,filter更为合适。结合本人使用心得,当你使用当前处理器与其他处理器公用一个传入变量时,使用流式处理,不要操作原对象;仅有当前处理器时,建议使用list自有方法,因为它速度更快。

<think>我们正在讨论如何使用Java Stream根据条件过滤或删除元素。根据引用内容,我们可以使用`filter()`方法来保留满足条件的元素,或者通过`filter()`与`collect()`结合来生成一个新的集合,从而实现“删除”不满足条件的元素的效果。注意,原集合不会被修改,因为Stream操作不会改变源数据。 引用[1]提到使用`filter()`方法筛选出符合条件的数据,引用[2]也展示了使用`filter()`进行条件过滤,引用[3]提到了在collect之后如何从原集合中删除(实际上是通过过滤后收集到新集合),引用[4]则展示了使用`filter()``findAny()`来查找符合条件的元素。 因此,我们可以这样操作: 1. 如果要保留满足条件的元素,使用`filter()`方法,然后收集到一个新的集合中。 2. 如果要删除满足条件的元素,可以在`filter()`中使用否定条件,然后收集到新的集合中。 注意:如果你希望直接修改原集合(而不是创建新集合),那么可以使用`removeIf()`方法,这是`Collection`接口提供的方法,它使用一个条件(Predicate)来删除元素。但是注意,`removeIf()`不是Stream API的一部分,而是集合本身的方法。 下面分别给出两种方式的示例: ### 方法1:使用Streamfilter()创建新集合(不改变原集合) ```java import java.util.List; import java.util.stream.Collectors; // 假设我们有一个Person类,有age属性 class Person { private int age; // 构造方法、gettersetter省略 } public class Main { public static void main(String[] args) { List<Person> people = ...; // 初始化 // 保留年龄大于18岁的人(即删除年龄小于等于18岁的人) List<Person> filteredList = people.stream() .filter(person -> person.getAge() > 18) .collect(Collectors.toList()); // 或者,删除年龄大于18岁的人(即保留年龄小于等于18岁的人) List<Person> removedList = people.stream() .filter(person -> person.getAge() <= 18) .collect(Collectors.toList()); } } ``` ### 方法2:使用removeIf()直接修改原集合(会改变原集合) ```java // 直接删除年龄大于18岁的人 people.removeIf(person -> person.getAge() > 18); // 或者,删除年龄小于等于18岁的人 people.removeIf(person -> person.getAge() <= 18); ``` 注意:`removeIf()`是直接在原集合上操作,会改变原集合的内容。而Stream的`filter()`不会改变原集合,而是生成一个新的集合。 根据引用[3]中提到的,我们也可以使用Stream的collect操作后,将原集合清空,再将新集合加入,但这样不如直接使用`removeIf()`高效。 总结: - 如果需要保留原集合不变,使用Stream的`filter()``collect()`。 - 如果希望直接修改原集合,使用`removeIf()`。 根据需求选择合适的方式。 相关问题: 1. Java Stream中如何同时使用多个条件进行过滤? 2. 如何使用Java Stream对集合元素进行分组? 3. Java中如何高效地合并两个集合?</think>在 Java 中使用 Stream 流根据条件过滤或删除元素,主要有以下几种高效方式: ### 方法 1:使用 `filter()` 创建新集合(推荐) 通过 `filter()` 保留满足条件的元素,生成新集合(不修改原集合): ```java List<Person> filteredList = people.stream() .filter(person -> person.getAge() > 18) // 保留年龄>18的元素 .collect(Collectors.toList()); // 收集到新集合 ``` - ✅ **优点**:线程安全,不改变原数据 - ❌ **缺点**:产生新集合对象 ### 方法 2:使用 `removeIf()` 直接修改原集合 通过集合的 `removeIf()` 方法直接删除元素(修改原集合): ```java people.removeIf(person -> person.getAge() <= 18); // 直接删除年龄≤18的元素 ``` - ✅ **优点**:原地操作,无额外内存开销 - ❌ **缺点**:会修改原始数据(需谨慎) --- ### 复杂场景处理 #### 场景 1:多条件过滤 ```java // 保留年龄>18 且 姓名以"J"开头的人 List<Person> result = people.stream() .filter(p -> p.getAge() > 18 && p.getName().startsWith("J")) .collect(Collectors.toList()); ``` #### 场景 2:删除后立即使用 ```java // 删除无效对象后统计剩余数量 long validCount = people.stream() .filter(Person::isValid) // 假设isValid是验证方法 .count(); ``` #### 场景 3:结合其他 Stream 操作 ```java // 删除重复对象(根据ID去重) List<Person> uniquePersons = people.stream() .filter(StreamUtils.distinctByKey(Person::getId)) // 自定义去重方法 .collect(Collectors.toList()); ``` --- ### 性能对比 | 方法 | 时间复杂度 | 空间复杂度 | 适用场景 | |--------------|------------|------------|----------------------| | `filter()` | O(n) | O(n) | 需保留原始数据时 | | `removeIf()` | O(n) | O(1) | 允许修改原集合时 | > 💡 **最佳实践**: > - 优先用 `filter()` 避免副作用 > - 大数据集用 `parallelStream()` 加速(需线程安全) > - 频繁删除操作考虑 `Iterator` 遍历 --- ### 注意事项 1. **空指针防护**: ```java .filter(p -> p != null && p.getAge() > 18) // 防止NPE ``` 2. **并行流同步**: ```java List<Person> safeList = Collections.synchronizedList(people); safeList.parallelStream().filter(...) // 多线程安全 ``` 3. **资源关闭**: ```java try(Stream<Person> stream = people.stream()) { stream.filter(...).forEach(...); // 确保流关闭 } ``` --- ### 相关问题 1. 如何用 Stream 实现两个集合对象的差集/并集/交集? 2. Stream 的 `parallelStream()` 在什么场景下会降低性能? 3. 如何用 `Collectors.groupingBy()` 实现按条件分组删除? 4. Java 中 `Iterator` `Stream` 删除元素的性能差异? > 示例引用:`filter()` 实现条件过滤[^2],`removeIf()` 直接修改集合[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值