如何对Java对象多字段进行自然排序?解决字母数字名称排序问题
解决字母数字类型Item Name的自然排序问题
你当前的排序代码如下:
Comparator<Item> itemComparator = Comparator.comparing(Item::getListId) .thenComparing(Item::getItemName); Collections.sort(itemList, itemComparator);
这段代码能按listId完成分组排序,但itemName属于字母数字组合(如Item 0、Item 101),默认字符串排序基于ASCII码,会出现数字逻辑顺序错误的情况(比如Item 0 → Item 101 → Item 28)。以下是几种简便的实现自然排序(数字按数值大小排序)的方案:
方案一:针对固定格式的快速实现
如果你的itemName格式固定为[前缀] [数字](比如示例中的Item XXX),可以直接提取数字部分转为整数作为排序依据,代码简洁高效:
Comparator<Item> itemComparator = Comparator.comparing(Item::getListId) .thenComparing(item -> { // 拆分名称提取数字段 String numSegment = item.getItemName().split(" ")[1]; return Integer.parseInt(numSegment); }); Collections.sort(itemList, itemComparator);
方案二:通用自然排序(无第三方依赖)
如果itemName格式不固定(前缀、数字位置可能变化),可以实现一个通用的自然排序比较器,兼容任意包含数字的字符串:
// 通用自然字符串比较器 Comparator<String> naturalStringComparator = (s1, s2) -> { int idx1 = 0, idx2 = 0; while (idx1 < s1.length() && idx2 < s2.length()) { if (Character.isDigit(s1.charAt(idx1)) && Character.isDigit(s2.charAt(idx2))) { // 提取连续数字序列并转为数值比较 long num1 = 0, num2 = 0; while (idx1 < s1.length() && Character.isDigit(s1.charAt(idx1))) { num1 = num1 * 10 + (s1.charAt(idx1) - '0'); idx1++; } while (idx2 < s2.length() && Character.isDigit(s2.charAt(idx2))) { num2 = num2 * 10 + (s2.charAt(idx2) - '0'); idx2++; } if (num1 != num2) { return Long.compare(num1, num2); } } else { if (s1.charAt(idx1) != s2.charAt(idx2)) { return Character.compare(s1.charAt(idx1), s2.charAt(idx2)); } idx1++; idx2++; } } return Integer.compare(s1.length(), s2.length()); }; // 应用到Item排序 Comparator<Item> itemComparator = Comparator.comparing(Item::getListId) .thenComparing(Item::getItemName, naturalStringComparator); Collections.sort(itemList, itemComparator);
方案三:借助第三方库简化代码
如果项目已引入Apache Commons Lang库,可直接使用内置的自然排序方法,代码最简洁:
import org.apache.commons.lang3.StringUtils; Comparator<Item> itemComparator = Comparator.comparing(Item::getListId) .thenComparing(Item::getItemName, StringUtils::naturalCompare); Collections.sort(itemList, itemComparator);
根据你提供的JSON示例数据,itemName格式固定,使用方案一即可满足需求,得到listId分组后,itemName按数字从小到大排列的结果。
内容的提问来源于stack exchange,提问作者Tiana
相关产品推荐
相关产品推荐

