zoukankan      html  css  js  c++  java
  • Java 使用 Stream API 筛选 List

    Java 使用 Stream API 筛选 List

    前言

    上课的时候看到老师用迭代器来遍历 List 中的元素的时候,我的内心是极其嫌弃的,这种迭代方法不能直接访问当前的元素,而且写起来也麻烦。于是上网查了查 Java 有没有类似于 Linq 的东西,虽然发现了一个 JLinq 但是抱着学习的心态,还是没有用这个东西。看了看 Intellji 的自动补全然后想出了下面的代码。

    题目

    删除 List 中信息重复的学生

    解法一

    LinkedList<T3.Student> repo3 = new T3.StudentTest().getRepo();
    repo3.removeIf(s->repo3.indexOf(s)!=repo3.lastIndexOf(s));

    这个方法看起来是没有很大的问题的,但是如果问题稍微变了一下,这就没用了。

    题目 update

    删除 List 中信息部分重复的学生,也就是只要姓名、年龄相同的学生就认定为信息重复,即使学号不同。

    解法二

    上面的解法一到了这个问题就失效了,对于这个问题我只能想到用下面的代码来解决

    for (int i = 0; i < repo3.size(); i++)
            {
                T3.Student stu = repo3.get(i);//Lambda 表达式不允许我用没被引用的变量,所以就把这句单独提了出来
                repo3.removeIf(s->s.equals(stu));//根据题意定义的 equals 方法
            }

    增加了一个 for 循环,其余的基本没变,但是代码的简洁程度相较于使用迭代器得到了大幅度提高。


    踩到的坑

    0.为毛不用foreach或者forEach循环?

    foreach不能适应动态变化的集合,因为我在动作中删除了元素。
    forEach虽然是一个内部循环,有并行计算的优势,但是还是由于上面的原因不能使用。

    1.Stream 接口的操作不会对原有的数据产生影响。

    repo3.removeAll(repo3.stream()
         .filter(
                 s -> repo3.stream().filter(stu -> stu.equals(s)).count() != 0)
         .collect(Collectors.toList()));

    本来我是想用这种方法拿到所有重复的元素,然而事实上是不行的,因为Stream 接口的操作不会对原有的数据产生影响。导致第二个 filter 会把所有元素重新扫描一遍,所以需要改成下面的代码:

    repo3.removeIf
            (
                    s -> repo3
                    .subList(repo3.indexOf(s),repo3.size())
                    .stream()
                    .filter(stu -> stu.equals(s))
                    .count() != 0
            );

    看起来好像比解法二复杂了许多但是在效率上有很大的进步,Stream API是并行化的,比外部循环不知道要高到哪里去了,然而这里还存在一个问题,就是在subList中获得对当前元素的索引的速度可能会拖慢效率,然而,在这道题目的测试用例当中学号起到了索引的作用,然后这里的效率可以大幅度提升。

    总结

    一开始准备用 Stream API 我是拒绝的,我看到它是以方法的形式出现的,我还以为会出现类型转换,后来发现这是 Java 缺少 extend methods 才出现的东西。然后这个东西实现了跟 Linq 差不多的功能,配合 Lambda 表达式很好用。
    那么下面给出最终的版本:

    repo3.removeIf
                    (
                            s -> repo3
                            .stream()
                            .filter(stu -> stu.equals(s))
                            .count() != 0
                    );

    这里之所以不需要把 list 截断可能是因为 removeif也是一个stream方法。

  • 相关阅读:
    lua判断字符串包含另一个字符串
    expect使用技巧
    Linux expect
    expect正则捕获返回结果
    修改alpine Linux的Docker容器的时区
    Dockerfile镜像优化,减小镜像
    Sed在匹配行前后加入一行
    scp的使用以及cp的对比
    rsync 的用法
    傅里叶系列(一)傅里叶级数的推导 (转)
  • 原文地址:https://www.cnblogs.com/grj001/p/12225598.html
Copyright © 2011-2022 走看看