我正在compareTo()为这样的简单类实现方法(以便能够使用Collections.sort()Java 平台提供的其他好东西):
compareTo()
Collections.sort()
public class Metadata implements Comparable<Metadata> { private String name; private String value; // Imagine basic constructor and accessors here // Irrelevant parts omitted }
我希望这些对象的 自然排序 是:1)按名称排序,2)如果名称相同,则按值排序;两种比较都应该不区分大小写。对于这两个字段,空值是完全可以接受的,因此compareTo在这些情况下不能中断。
compareTo
想到的解决方案如下(我在这里使用“保护条款”,而其他人可能更喜欢单个返回点,但这不是重点):
// primarily by name, secondarily by value; null-safe; case-insensitive public int compareTo(Metadata other) { if (this.name == null && other.name != null){ return -1; } else if (this.name != null && other.name == null){ return 1; } else if (this.name != null && other.name != null) { int result = this.name.compareToIgnoreCase(other.name); if (result != 0){ return result; } } if (this.value == null) { return other.value == null ? 0 : -1; } if (other.value == null){ return 1; } return this.value.compareToIgnoreCase(other.value); }
这可以完成工作,但我对这段代码并不完全满意。诚然,它不是 很 复杂,但相当冗长乏味。
问题是, 您将如何减少冗长 (同时保留功能)?如果有帮助,请随意参考 Java 标准库或 Apache Commons。使这(一点)更简单的唯一选择是实现我自己的“NullSafeStringComparator”,并将其应用于比较两个字段吗?
编辑 1-3 : Eddie 是对的;修复了上面的“两个名字都为空”的情况
我在 2009 年问过这个问题,当然是在 Java 1.6 上,当时 Eddie 的纯 JDK 解决方案 是我首选的公认答案。直到现在(2017 年),我才开始改变它。
还有3rd 方库解决方案——2009 Apache CommonsCollections 一个和一个 2013 Guava 一个,都是由我发布的——我在某个时间点确实更喜欢。
我现在将Lukasz Wiktor 的干净Java 8 解决方案作为公认的答案。如果在 Java 8 上,这绝对是首选,而如今 Java 8 应该可用于几乎所有项目。
使用 Java 8 :
private static Comparator<String> nullSafeStringComparator = Comparator .nullsFirst(String::compareToIgnoreCase); private static Comparator<Metadata> metadataComparator = Comparator .comparing(Metadata::getName, nullSafeStringComparator) .thenComparing(Metadata::getValue, nullSafeStringComparator); public int compareTo(Metadata that) { return metadataComparator.compare(this, that); }