【问题】使用Collections.sort()进行list集合排序问题

背景:
最近定位了一个list集合排序乱序问题,算是比较典型的问题,在此分享一下。

问题描述
使用集合中Collections.sort()方法对list集合排序时,排序的结果中出现了乱序问题,问题代码如下:

CarRecord .java:

package com.sk.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CarRecord implements Comparable<CarRecord> {

    private Integer id;
    private String plateCode;
    private Long passTime;

    @Override
    public int compareTo(CarRecord o) {
        return (int) (o.passTime - this.passTime);
    }
}

Test.java

package com.sk.test;

import com.sk.bean.CarRecord;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

public class Test01 {

    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<CarRecord> list = new ArrayList<>();
        list.add(new CarRecord(1, "鲁A 12345", 1688634366000L));
        list.add(new CarRecord(2, "鲁A 12346", 1688568125000L));
        list.add(new CarRecord(3, "鲁A 12347", 1688504221000L));
        list.add(new CarRecord(4, "鲁A 12348", 1686144663000L));
        list.add(new CarRecord(5, "鲁A 12349", 1686094000000L));
        list.add(new CarRecord(5, "鲁A 12349", 1686043339000L));
        list.add(new CarRecord(5, "鲁A 12349", 1685992410000L));
        Collections.sort(list);
        list.stream().forEach(x -> {
            System.out.println(x.toString() + "  时间:" + sdf.format(new Date(x.getPassTime())));
        });
    }
}

执行结果:

CarRecord(id=4, plateCode=A 12348, passTime=1686144663000)  时间:2023-06-07 21:31:03
CarRecord(id=5, plateCode=A 12349, passTime=1686094000000)  时间:2023-06-07 07:26:40
CarRecord(id=5, plateCode=A 12349, passTime=1686043339000)  时间:2023-06-06 17:22:19
CarRecord(id=5, plateCode=A 12349, passTime=1685992410000)  时间:2023-06-06 03:13:30
CarRecord(id=1, plateCode=A 12345, passTime=1688634366000)  时间:2023-07-06 17:06:06
CarRecord(id=2, plateCode=A 12346, passTime=1688568125000)  时间:2023-07-05 22:42:05
CarRecord(id=3, plateCode=A 12347, passTime=1688504221000)  时间:2023-07-05 04:57:01

我们按照passTime字段进行排序,通过观察执行结果能够明显发现数据的passTime字段是存在乱序的。

问题原因:
通过分析代码发现问题出现在代码(int) (o.passTime - this.passTime)上,我们知道java中long和int类型的数值长度返回是不一样的,时间o.passTime - this.passTime差值的范围超过int数值范围时,强制转int类型会造成数据丢失;
注:
**int**的取值范围为(-2147483648~2147483647),占用4个字节(-2的31次方到2的31次方-1) ;
**long**的取值范围为(-9223372036854774808~9223372036854774807),占用8个字节(-2的63次方到2的63次方-1);
id3的passtime-id4的passtime值:1688504221000-1686144663000=2359558000 > 2147483647
由上可知,相同年月的passtime之间的差值在int数值时间范围内,所以相同年月的数据是有序的。

问题解决:

代码修改:(int) (o.passTime - this.passTime)修改成compare(o.passTime, this.passTime),即:

Collections.sort(list, new Comparator<Long>() {
    @Override
    public int compare(Long l1, Long l2) {
        return Long.compare(l1,l2);
    }
});

查看compare()方法的源码,如下:

public static int compare(long x, long y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

修改后的执行结果:

CarRecord(id=1, plateCode=A 12345, passTime=1688634366000)  时间:2023-07-06 17:06:06
CarRecord(id=2, plateCode=A 12346, passTime=1688568125000)  时间:2023-07-05 22:42:05
CarRecord(id=3, plateCode=A 12347, passTime=1688504221000)  时间:2023-07-05 04:57:01
CarRecord(id=4, plateCode=A 12348, passTime=1686144663000)  时间:2023-06-07 21:31:03
CarRecord(id=5, plateCode=A 12349, passTime=1686094000000)  时间:2023-06-07 07:26:40
CarRecord(id=5, plateCode=A 12349, passTime=1686043339000)  时间:2023-06-06 17:22:19
CarRecord(id=5, plateCode=A 12349, passTime=1685992410000)  时间:2023-06-06 03:13:30

阿里《java开发手册》中对Collections.sort()规范要求:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用stream排序的方式是通过将集合转换成流,然后使用sorted方法进行排序。具体步骤如下: 1. 首先,将集合转换为流,可以使用stream()方法将集合转换为流,例如:List<Student> studentList = new ArrayList<>(); Stream<Student> studentStream = studentList.stream(); 2. 接下来,使用sorted方法进行排序。在sorted方法中,我们可以传入一个Comparator对象,用于指定排序的规则。比如,按照学生的年龄进行降序排序,可以使用Comparator.comparing方法,然后通过reversed方法进行降序排序。示例代码如下: studentList = studentList.stream() .sorted(Comparator.comparing(Student::getAge).reversed()) .collect(Collectors.toList()); 3. 最后,将排序后的流收集回集合中,可以使用collect方法将排序后的流收集成一个新的集合。示例代码如下: List<Student> sortedList = studentList.stream() .sorted(Comparator.comparing(Student::getAge).reversed()) .collect(Collectors.toList()); 请注意,以上代码只是示例,具体的排序规则和集合类型需要根据实际情况进行调整。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Java的集合排序Collections.sortlist.sortlist.stream().sorted方法详解](https://blog.csdn.net/qq_42971035/article/details/109132219)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [性能对比:collections.sort vs treeSet sort vs java8 stream.sorted](https://blog.csdn.net/weixin_42306480/article/details/114207280)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dylan~~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值