据说当输入参数为null时,compareTo()应抛出NullPointerException。但是,我正在实现一个需要将字段与String类型进行比较的类。这些字段不必是强制性的。我想知道在这种情况下,
1)当输入为空时我应该返回什么?是否任何非空字符串按字典顺序大于或小于null?
和
2)如果这被认为是不好的做法,是否有任何支持性论点?我应该强制用户使用空字符串吗?如果使用空字符串,那不会混淆字段不适用的情况和字段为空的情况吗?如果必须抛出异常,那么除了在手册中警告用户之外,还有什么可以/我应该做什么?
编辑:我可能不会在这里清楚地表达自己,但在我正在实现的程序中,可以为null的字符串是所有字段或类,不应该为null。换句话说,comparisonTo()使用的对象不能为null,只能是它们的私有字段。所以在这种情况下,我相信如果我正确地实现了compareTo(),它就不会违反传递要求,因为具有空字段的类总是被认为是相同的。我是对的还是我在解释这个错误?谢谢大家的答案!
答案 0 :(得分:25)
请注意,null不是。的实例 任何类,和e.compareTo(null) 应抛出NullPointerException 即使e.equals(null)返回 假的。
答案 1 :(得分:13)
是的,允许null
实例字段没有问题 - 只需确保定义其排序顺序。最自然的是在所有真正的弦之前或之后放置它,但你可以在这里做任何事情,只是一贯地做。 (例如,您可以像null
那样对"null"
进行排序。)
以下是单个成员的示例实现:
class Example implements Comparable<Example> {
@Nullable
private String member;
// TODO: getter, setter, constructor, ...
public int compareTo(Example that) {
if(this.member == null)
if(that.member == null)
return 0; //equal
else
return -1; // null is before other strings
else // this.member != null
if(that.member == null)
return 1; // all other strings are after null
else
return this.member.compareTo(that.member);
}
}
请注意,Comparable.compareTo()的规范只有o.compareTo(null)
的约束(它应该像- null.compareTo(o)
一样,即抛出NullPointerException),但不是{{1}处理字段(它根本没有提到字段,因此只要确保反对称性,反身性和传递性,类就可以返回它想要的任何东西。)
答案 2 :(得分:7)
不抛出异常是不好的做法,因为它违反了compareTo的传递反对称性质。
来自Comparable.compareTo文档:
实施者必须确保 sgn(x.compareTo(y))== -sgn(y.compareTo(x))表示所有x和y。 (这意味着x.compareTo(y)必须 抛出异常iff y.compareTo(x) 抛出异常。)
实施者还必须确保这一点 这种关系是传递性的: (x.compareTo(y)&gt; 0&amp; y.compareTo(z)&gt; 0) 暗示x.compareTo(z)> 0。
最后,实施者必须确保 x.compareTo(y)== 0意味着 sgn(x.compareTo(z))== sgn(y.compareTo(z)),适用于所有z。
更重要的是,在对象上使用compareTo将它们与字符串进行比较是一个坏主意,原因相同:sign(obj.compareTo(str)) != -sign(str.compareTo(obj))
。实现自定义Comparator并在其中执行任何操作。
答案 3 :(得分:3)
由于compareTo
的文档声明它应该抛出NullPointerException
,因此您应该遵循这些准则,以便您的实现与界面文档保持一致。这也解决了非空字符串是否在字典上小于或大于null
的问题。
您有几个选项可以解决这个问题。如果为空且不适用不同,那么您应该将字符串字段包装在您自己的字段类中。例如,假设您可以创建一种可能具有isApplicable
方法的MyField类型,该方法指示该字段是否适用于此情况(或类似的情况)。或者您可以重新考虑您的设计并确保空字符串和N / A确实是两个不同的东西。如果是,你需要一种方法来区分这两者。
答案 4 :(得分:3)
您需要确定null是否大于或小于非null值。您可以设计compareTo
以满足班级自然顺序的需要,因此这不是一种不好的做法。
答案 5 :(得分:0)
除了接受Paulo Ebermann的答案之外,如果您需要处理 ASC / DESC 订单,则可以这样做。 (我们假设NULL总是按正常的升序排在非NULL之前,否则降序。)
final boolean sortAsc = false; // Suppose this TRUE/FALSE is for ASC/DESC
objects.sort(new Comparator<Example>() {
@Override
public int compare(Example e1, Example e2) {
if (e1.getMember() == null && e2.getMember() == null) {
return 0; // Both NULLs are equal
}
else if (e1.getMember() == null && e2.getMember() != null) {
return sortAsc ? -1 : 1; // NULLs should precede non-NULLs in ascending order, follow in descending order
}
else if (e1.getMember() != null && e2.getMember() == null) {
return sortAsc ? 1 : -1; // Non-NULLs should follow NULLs in ascending order, precede in descending order
} else {
// Both non-NULLs
return sortAsc ? e1.getMember().compareTo(e2.getMember())
: e2.getMember().compareTo(e1.getMember());
}
}
});