今天做一个功能,需要把博客按年份进行归档,年份需要使用倒序。
思路
我的思路是,先查出所有的年份,并且直接倒序。然后查询出每一个年份下的所有博客,把这些博客加到一个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慢