如何对包含Etape对象的列表按Etat与日期进行复合排序?
问题原因及解决方案
核心原因分析
你遇到的日期排序失效问题,大概率是两种排序场景的逻辑不一致导致的:
- 单独按日期排序时,你可能**将String类型的date解析为了日期对象(比如LocalDate、Date)**进行比较,利用日期的自然时序排序;
- 而使用
sortedWith(compareBy(...))组合排序时,直接用了String类型的date做字典序比较——当日期字符串格式不是ISO标准格式(如yyyy-MM-dd)时,字典序和实际日期时序会出现偏差,看起来就像是日期排序失效。
还有一种小概率情况:如果Etat枚举的compareTo逻辑被重写过,导致同Etat的元素被错误判定为不相等,但你提到单独按Etat排序正常,这种可能性较低。
正确的组合排序写法
解决问题的核心是:组合排序时,对date字段使用日期对象而非字符串进行比较。以下是Java/Kotlin的正确示例:
Kotlin 示例
// 先按Etat枚举的ordinal排序(Valide(0)在前),再按解析后的LocalDate排序 val sortedList = etapeList.sortedWith( compareBy<Etape>( { it.etat }, // 第一排序键:Etat枚举,默认按ordinal比较 { LocalDate.parse(it.echeancier.date) } // 第二排序键:解析为LocalDate后比较 ) )
如果日期字符串不是ISO格式,需要指定格式化器:
val dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy") val sortedList = etapeList.sortedWith( compareBy<Etape>( { it.etat }, { LocalDate.parse(it.echeancier.date, dateFormatter) } ) )
Java 示例
// 使用Comparator.comparing组合排序 List<Etape> sortedList = etapeList.stream() .sorted(Comparator.comparing(Etape::getEtat) // 第一排序键:Etat枚举 .thenComparing(etape -> LocalDate.parse(etape.getEcheancier().getDate()))) // 第二排序键:解析为LocalDate .collect(Collectors.toList());
非ISO格式日期的处理:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); List<Etape> sortedList = etapeList.stream() .sorted(Comparator.comparing(Etape::getEtat) .thenComparing(etape -> LocalDate.parse(etape.getEcheancier().getDate(), dateFormatter))) .collect(Collectors.toList());
验证点
- 确认日期字符串格式,确保解析时不会抛出异常;
- 可以在比较器中添加日志,验证同Etat的元素是否触发了日期比较逻辑。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

