文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么解决使用Hashcode中distinct()方法没有起效问题

2024-04-02 19:55

关注

本篇内容介绍了“怎么解决使用Hashcode中distinct()方法没有起效问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

大佬的疑惑

大佬在项目中写了类似这样的一段代码:

List<ProjectId> list = new ArrayList<>(); // 省略add数据操作 List<DeviceModel> models =  list.stream().map(ProjectId::getDeviceModel).distinct().collect(Collectors.toList()); System.out.println(models);

结果呢,这段代码中的distinct()方法并没有起效,并没有达到去重的预期。

通过API文档来看并没有问题,进而大佬开启了debug模式,发现奇怪的是实体类的equals方法都没进。

解决思路

根据大佬发的部分代码和实现思路,把整个模拟的测试程序补充完整,创建了两个实体类ProjectId和DeviceModel,并重写了equals方法(跟大佬沟通,他重写了equals方法,并且单独使用是生效的)。

DeviceModel实体类,简单重写了equals方法,只比较字段no是否相等。

@Data public class DeviceModel {      private String no;      @Override     public String toString(){         return no;     }      @Override     public boolean equals(Object other) {          if (this == other) {             return true;         }         if (other == null || getClass() != other.getClass()) {             return false;         }          return this.toString().equals(other.toString());     } }

ProjectId实体类,重写了equals方法,

@Data public class ProjectId {      private int id;      private DeviceModel deviceModel; }

然后,构建了测试类:

public class Test {      public static void main(String[] args) {          List<ProjectId> list = new ArrayList<>();          DeviceModel device1 = new DeviceModel();         device1.setNo("1");         ProjectId projectId1 = new ProjectId();         projectId1.setDeviceModel(device1);         projectId1.setId(1);         list.add(projectId1);          DeviceModel device2 = new DeviceModel();         device2.setNo("1");         ProjectId projectId2 = new ProjectId();         projectId2.setDeviceModel(device2);         projectId2.setId(1);         list.add(projectId2);          DeviceModel device3 = new DeviceModel();         device3.setNo("2");         ProjectId projectId3 = new ProjectId();         projectId3.setDeviceModel(device3);         projectId3.setId(2);         list.add(projectId3);                 List<DeviceModel> models =  list.stream().map(ProjectId::getDeviceModel).distinct().collect(Collectors.toList());        System.out.println(models);      } }

先构建了一组数据,然后让device1与device2的no属性一样,重写了equals方法,理论上它们应该是相等的,device3对象用来做对照。

执行上面的程序,控制台打印如下:

[1, 1, 2]

的确还原了大佬的bug,也奇怪为什么会这样。但既然bug已重现,解决就是比较简单的事了。

此时,大佬又发来另外一个线索,说通过for循环形式没事:

List<DeviceModel> results = new ArrayList<>(); for (DeviceModel deviceModel : list.stream().map(ProjectId::getDeviceModel).collect(Collectors.toList())) {     if (!results.contains(deviceModel)) {         results.add(deviceModel);     } } System.out.println(results);

这种实现形式恰好又可以用来做对照。

问题排查

进行问题排查时首先也想到了debug,但是同样出现并未走equals方法的情况。

仔细看了一下代码,发现在Stream处理的过程中用到了map操作。而在之前的文章中也提到,Map中判断一个对象是否已经存在是先通过key的hash值定位到对应的数组下标,如果该位置上的Entry没有值,则直接保存;如果已经有存在的值,再通过equals方法比较值是否一样。

那么,是不是因为重写了equals方法,而没有重写hashcode方法导致的呢?于是,在DeviceModel类中新增了hashcode方法:

@Override public int hashCode() {     // JDK7新增的Objects工具类     return Objects.hash(no); }

再次执行,测试方法,发现可以成功去重了。很显然,大佬的失误是在重写equals方法时违背了一条原则:如果一个类的equals方法相等,那么它们的hashcode方法必须相等。由于没有重写hashcode方法导致违背这一原则。因此,在隐式使用Map时就出现了莫名其妙的问题。

后续

经过这一番周折,问题终于解决。想必大家更也更加明白了为什么重写equals方法一定要重写hashcode方法了。后面大佬又考问我一个问题:为什么list.contains方法不会出现这个问题呢?

因为List的底层结构是数组,不像Map那样为了提升效率先对Key进行hash处理比较。简单看一下ArrayList中contains方法的核心实现:

public int indexOf(Object o) {     if (o == null) {         for (int i = 0; i < size; i++)             if (elementData[i]==null)                 return i;     } else {         for (int i = 0; i < size; i++)             if (o.equals(elementData[i]))                 return i;     }     return -1; }

可以看出如果对象不为null时,还是循环调用的equals方法来处理的。

“怎么解决使用Hashcode中distinct()方法没有起效问题”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯