仅修改getValueForComparator实现Java列表反向排序的方案风险探讨
字符反转实现字符串降序排序的缺陷分析
原代码与功能
原Java代码通过自定义比较器,调用getValueForComparator()返回的字符串实现列表按AClass.name升序排序:
static record AClass(String name, int id) { public String getValueForComparator() { return this.name; } } static class UnmodifiableAComparator implements Comparator<AClass>{ @Override public int compare(AClass o1, AClass o2) { return o1.getValueForComparator().compareTo(o2.getValueForComparator()); } } public static void main(String[] args) { List<AClass> myList = Arrays.asList( new AClass("C", 1), new AClass("A", 3), new AClass("B", 2)); myList.sort(new UnmodifiableAComparator()); for (AClass obj: myList) { System.out.println(obj); } }
执行后输出结果:
AClass[name=A, id=3] AClass[name=B, id=2] AClass[name=C, id=1]
需求说明
要求仅修改getValueForComparator()方法,实现按AClass.name降序排序。类比int类型取反实现降序的思路:
// 原升序逻辑 public int getValueForComparator() { return this.id; } // 修改为降序 public int getValueForComparator() { return -this.id; }
用户提出的字符反转方案
用户尝试通过反转每个字符的方式实现字符串降序,代码如下:
public String getValueForComparator() { StringBuilder sb = new StringBuilder(); for (char c: this.name.toCharArray()) { char cInvert = (char) (256 - c); sb.append(cInvert); } return sb.toString(); }
方案存在的缺陷与边界问题
这个方案存在多处严重问题,完全不具备通用性:
- 完全不兼容Unicode字符:Java的
char采用UTF-16编码,取值范围是0~65535,但代码中仅用256 - c处理,只覆盖了0~255的ASCII字符。对于中文、日文等非ASCII Unicode字符(例如'中'的char值为20013),计算后会得到负数,强制转换为char会变成无效的乱码字符,此时compareTo的排序逻辑完全失效,根本无法实现预期的降序效果。 - ASCII字符范围内的排序逻辑也有错误:ASCII中的控制字符(031)反转后的值会大于所有可打印ASCII字符(32126)的反转值。比如ASCII 0反转后是256,在字符串比较中会被判定为大于'~'(ASCII 126)的反转值130,导致原本升序中最小的控制字符,在降序排序中反而排在最前面,完全不符合预期。
- 字符串长度不同时逻辑失效:例如原字符串"A"和"AB",升序中"A" < "AB",降序应是"AB" < "A"。但反转后,"A"的反转值是单个字符191,"AB"的反转值是"191190"。调用
compareTo时,先比较第一个字符(相同),再比较长度,短字符串会被判定为更小,即反转后的"A" < "AB",对应原比较逻辑会把"A"排在"AB"前面,和预期的降序结果相反。
内容的提问来源于stack exchange,提问作者Hadi
相关产品推荐
相关产品推荐

