实现字母数字值排序,现有Java比较器代码无法输出预期结果
问题排查与修正方案
现有代码的问题
- 笔误错误:判断第二个对象值是否为数字时调用了
o2.v(),应该改为o2.getnumber(),该错误会导致只要第二个值非纯数字,就直接进入字符串比较分支,逻辑完全错乱。 - 核心逻辑缺陷:只要两个值不同时为纯数字,就直接使用字符串原生字典序比较,没有提取数字前缀做优先比较。例如测试用例中的
728R和1234,按现有逻辑字符串比较时1234首字符ASCII码更小,会排在728R前面,不符合预期。 - 边界处理违规:当其中一个值为null、或排序参数不是asc/desc时直接返回0,违反比较器的一致性约定,会导致排序结果混乱。
修正思路
不需要区分纯数字和带字母的串,统一按以下规则比较即可符合需求:
- 提取两个字符串的最长数字前缀,转换为数值做优先比较,数值小的整体排前面
- 若数字前缀的数值相等,再直接比较整个字符串的字典序即可(不对字母做单独优先级处理)
修正后代码示例
public int compare(SO o1, SO o2) { String num1 = o1.getnumber(); String num2 = o2.getnumber(); // 先处理null的情况,这里约定null排在非null前面,可根据需求调整 if (num1 == null && num2 == null) return 0; if (num1 == null) return "asc".equals(searchSO.getSortOrder()) ? -1 : 1; if (num2 == null) return "asc".equals(searchSO.getSortOrder()) ? 1 : -1; // 提取数字前缀 long prefix1 = extractNumberPrefix(num1); long prefix2 = extractNumberPrefix(num2); int prefixCompare = "asc".equals(searchSO.getSortOrder()) ? Long.compare(prefix1, prefix2) : Long.compare(prefix2, prefix1); if (prefixCompare != 0) { return prefixCompare; } // 前缀相同则比较完整字符串 return "asc".equals(searchSO.getSortOrder()) ? num1.compareTo(num2) : num2.compareTo(num1); } // 提取字符串开头的数字前缀,没有数字则返回0,可根据需求调整默认值 private long extractNumberPrefix(String str) { StringBuilder sb = new StringBuilder(); for (char c : str.toCharArray()) { if (Character.isDigit(c)) { sb.append(c); } else { break; } } if (sb.length() == 0) { return 0L; } // 数字过长的场景可以自行捕获异常做降级处理 return Long.parseLong(sb.toString()); }
内容的提问来源于stack exchange,提问作者Selina
相关产品推荐
相关产品推荐

