要时刻记住HashMap是无序的,想要有序可以用LinkedHashMap,内含HashMap和和LinkedHashMap和的区别

今天做一个功能,需要把博客按年份进行归档,年份需要使用倒序。

思路

我的思路是,先查出所有的年份,并且直接倒序。然后查询出每一个年份下的所有博客,把这些博客加到一个list中,也就是一个年份有一个list。然后年份做key,list做value,把所有的博客保存到Map中。然后在渲染到前端页面就好了。

查表语句

    // 获取到倒序排序的年份list集合
    // select date_format(b.update_time,'%Y') as year from t_blog b group by year order by year desc;
    @Query("select function('date_format',b.updateTime,'%Y') as year from Blog b group by function('date_format',b.updateTime,'%Y') order by year desc")
    List<String> findGroupYear();

    // 根据年份查询出所有博客
    // select * from t_blog b where date_format(b.update_time, '%Y') = '2020' order by b.updateTime desc";
    @Query("select b from Blog b where function('date_format',b.updateTime,'%Y') = ?1 order by b.updateTime desc")
    List<Blog> findByYear(String year);
    // 归档,同一年的存放到一个list中,list存放在map中,年份是key,list是value
    @Override
    public Map<String, List<Blog>> archiveBlog() {
        List<String> years = blogRepository.findGroupYear();// 获取到倒序排序的年份list集合,大到小
        Map<String, List<Blog>> map = new HashMap<>();
        for(String year : years){
            map.put(year, blogRepository.findByYear(year));// 根据年份查询出所有博客,并加入map中
        }
        return map;
    }

 实际效果

理想很丰满,但是实际的效果有偏差。年份并没有倒序,而是相反的顺序。

排查过程

看到是相反的顺序,我刚开始一直以为是查询语句有问题,但是我检查了好多遍都没有发现问题。我还把查表语句翻译成了SQL语句,在MySQL上跑了一遍,没发年份的顺序现有问题。

然后我加了一句输出,发现年份真的没有问题。

    @Override
    public Map<String, List<Blog>> archiveBlog() {
        List<String> years = blogRepository.findGroupYear();// 获取到倒序排序的年份list集合,大到小
        Map<String, List<Blog>> map = new HashMap<>();
        for(String year : years){
            System.out.println("年份年份==" + year);
            map.put(year, blogRepository.findByYear(year));// 根据年份查询出所有博客,并加入map中
        }

        return map;
    }

然后我觉得看到是输出的下一句出了问题。

果不其然,我使用的是HashMap,这是无序的,所以正确顺序的年份存进去,很难保证顺序不会改变。

想要有顺序的Map,可以使用LinkedHashMap。我改回LinkedHashMap之后,终于正常显示了。

反思

基础知识真的很重要,还是好好复习吧。

下面引用一下“Eve2019”博主的对比,大家一起复习一下。

HashMap

  • Map存储过程:计算key的hashCode值,确定位置;如果位置上有元素,用equals判断是否一致,如果一致,不存,如果不一致,遍历下一个节点继续判断equals。注:添加是添加到链表的尾部。
  • 加载因子(扩容条件):默认0.75,空间存储75%后扩容。
  • 扩容:将原来的元素重新计算位置再存入;计算需要时间,因此不可以频繁扩容,扩容是成倍的。
  • HashMap根据键可以很快找到他的值,因此具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。
  • HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。
  • HashMap的键只允许一条为null,值可以多个为null

LinkedHashMap——有序的Map

  • 使用Map接口的哈希表和链表实现,具有可预知的迭代顺序。此实现与HashMap的不同之处在于:LinkedHashMap维护着一个双向循环链表。此链表定义了迭代顺序,该迭代顺序通常就是存放元素的顺序。
  • 如果在Map中重新存入已有的key,那么key的位置不会发生改变,只是将value值替换。
  • LinkedHashMap的内部维持了一个双向链表,保存了数据的插入顺序,遍历时,先得到的数据便是先插入的
  • 遍历速度比HashMap慢
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值