zoukankan      html  css  js  c++  java
  • 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方法。

  • 相关阅读:
    jmeter beanshell 从文件中获取随机参数
    shell 备份mysql
    Centos7 搭建wordpress
    jmeter分布式测试
    centos 环境搭建jenkins服务
    VMVare 虚拟机使用桥接模式
    Gradle 打可执行jar包
    appium 报错
    corda
    android构建过程
  • 原文地址:https://www.cnblogs.com/JacZhu/p/5398112.html
Copyright © 2011-2022 走看看