V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
luxinfl
V2EX  ›  程序员

这种去重方法真的有用么

  •  
  •   luxinfl · 2022-07-06 16:20:48 +08:00 · 3725 次点击
    这是一个创建于 875 天前的主题,其中的信息可能已经有所发展或是发生改变。

    为什么 copy 下来运行就报错,空指针,不清楚在网上的例子是怎么跑的

    studentList = studentList.stream().collect(
      Collectors.collectingAndThen(
         Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getName))), ArrayList::new));
        
    

    不知道为啥 string 类型字段就报错空指针,int 没错。

    就是为了要去重重复对象,重复对象的判断条件是某个字段的值相同。找了好多都是这么写的,但是一跑就报错。很神奇。

    22 条回复    2022-07-08 21:29:58 +08:00
    AoEiuV020CN
        1
    AoEiuV020CN  
       2022-07-06 16:34:01 +08:00
    最好上个完整一点点的代码,
    然后是哪个对象在哪里空了,期望是什么,
    这里 stream 可读性很糟糕,不如 for 循环,或者 addAll ,
    luxinfl
        2
    luxinfl  
    OP
       2022-07-06 16:39:33 +08:00
    @AoEiuV020CN 我搞出来了,tm 是别人传的数据有问题。。一个列表里面有个对象搞错字段了。。。
    nothingistrue
        3
    nothingistrue  
       2022-07-06 17:04:09 +08:00
    原理是,利用 Set 不允许添加重复元素的特性(添加重复元素时忽略,不是报错)来去重。具体操作是,将当前集合的所有元素尝试全部放入一个 Set 中(用哪个 Set 的实现类取决于如何判重),然后在将完成的 Set 转换回原来的集合,在将元素放入到 Set 中的时候,重复元素会被排除掉。但是你抄这段代码可读性是真特么差。
    nothingistrue
        4
    nothingistrue  
       2022-07-06 17:13:24 +08:00
    尝试换一种写法:

    studentList = new TreeSet<>(Comparator.comparing(Student::getName)).addAll(studentList).stream().collect(Collectors.toList())
    zhuangzhuang1988
        5
    zhuangzhuang1988  
       2022-07-06 17:20:00 +08:00
    还是写简单的 foreach 吧
    这样看真难看懂
    《 effective java 》里也有 stream 的讨论,不要无脑 stream
    codingadog
        6
    codingadog  
       2022-07-06 17:21:01 +08:00
    数据量不大的话不如直接 removeIf 。

    Set<String> tmp = new HashSet<>();
    studentList.removeIf(student -> !tmp.add(student.getName()));
    Leviathann
        7
    Leviathann  
       2022-07-06 17:23:00 +08:00
    换个库把,stream 除了 parallel 功能,其他完全没 eclipse collection 好用,性能也不如,java 官方的视频都说 eclipse collection 的抽象程度更高且性能也更好
    nothingistrue
        8
    nothingistrue  
       2022-07-06 17:28:09 +08:00
    好吧,我写错了,addAll 不能链式操作,要想一句代码就完成的话,只能使用原先那段很难看的代码。为了可读性建议拆分语句如下:

    TreeSet<Student> tempSet = new TreeSet<>(Comparator.comparing(Student::getName));
    tempSet.addAll(studentList);
    studentList = new ArrayList(tempSet); // 或者 studentList = tempSet.stream().collect(Collectors.toList());
    xinhochen
        9
    xinhochen  
       2022-07-06 17:42:20 +08:00
    我觉得这样写更容易理解一些:
    Set<String> filter = new HashSet<>();
    List<Student> result = studentList.stream().filter(o -> filter.add(o.getName())).collect(Collectors.toList());
    rpish
        10
    rpish  
       2022-07-06 17:45:58 +08:00
    好奇问下,大家项目开发中 stream 用得多吗?
    Red998
        11
    Red998  
       2022-07-06 17:55:44 +08:00   ❤️ 1
    用的很多 jdk8 stream 流用的很多
    chendy
        12
    chendy  
       2022-07-06 18:04:08 +08:00
    studentList = new ArrayList<>(new HashSet<>(studentList));
    mazai
        13
    mazai  
       2022-07-06 18:06:20 +08:00
    只是因为 students 中 name 有 null 的学生吧。 还有只是去重不用这么麻烦,重写 Student 对象的 hashcode 和 equals 方法,studentList.stream().distinct().collect(Collectors.toList()); 就行了
    git00ll
        14
    git00ll  
       2022-07-06 18:41:46 +08:00
    这么写可读性贼差
    golangLover
        15
    golangLover  
       2022-07-06 19:22:15 +08:00 via Android
    @mazai 同意有 null 的解释
    但不同意重写 equal. 可能我只是需要比较这个属性一次
    potatowish
        16
    potatowish  
       2022-07-06 19:28:24 +08:00 via iPhone
    @git00ll 可以抽一个常用的方法出来,每次这么写一堆确实难受
    lmshl
        17
    lmshl  
       2022-07-06 21:42:24 +08:00

    归根结底还是 Java 设计的 API 太丑了,丑破天际,搁 Scala 里就一行的事
    val result = studentList.distinctBy(_.name)
    wolfie
        18
    wolfie  
       2022-07-07 11:32:55 +08:00
    骚操作 new ArrayList(toMap(getName()).values())
    Anshay
        19
    Anshay  
       2022-07-07 11:39:39 +08:00
    直接 studentList.stream().distinct.toCollect.....即可,前提是有自己编写了 studentList 中的 equals 方法和 hashCode 方法。
    mazai
        20
    mazai  
       2022-07-07 14:19:56 +08:00
    @golangLover equals 和 hashcode 具体选取哪些字段重写还是看业务,哪几个字段能代表学生的唯一性,那就重写哪几个字段
    issakchill
        21
    issakchill  
       2022-07-07 14:46:29 +08:00
    streamEx 有些方法还挺好用的 也自带根据某字段去重的方法
    golangLover
        22
    golangLover  
       2022-07-08 21:29:58 +08:00 via Android
    @mazai 。。你是不可能一两次比较就重写字段的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1376 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 69ms · UTC 17:37 · PVG 01:37 · LAX 09:37 · JFK 12:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.