之前有人问过,但我没有找到一个体面的实施解释。
public int compareTo(Object o)
{
if (this == null || o == null)
{
return 0;
}
Tok tmp = (Tok) o;
if (this.rang < tmp.rang)
{
return -1;
} else if (this.rang > tmp.rang ) {
return 1;
} else {
return 0;
}
}
我读了两个我发现的类似问题;他们坚持要实施另一种方法。我不明白为什么这不起作用。该方法获取一个额外的对象,它检查它是否是一个有效的实例,或null
,如果null
只返回0
;什么是实现null-safe compareTo
的最简单方法。
对我有用的实施是:
public int compareTo(Object o)
{
if (o == null)
{
return 0;
}
Tok tmp = (Tok) o;
if (this.rang < tmp.rang)
{
return -1;
} else if (this.rang > tmp.rang ) {
return 1;
} else {
return 0;
}
}
这不是最佳实施,应该看看好人们在这里发布的答案。对于我的特殊情况,这是足够好,因为它永远不会为null,但接收到的对象可以为null,如果任何一个为null,则初始实现状态返回0.因此,如果给定对象为null,则返回0。
答案 0 :(得分:12)
就个人而言,我喜欢Guava's Ordering
进行无效安全比较。您可以指定#nullsFirst()
或#nullsLast()
以避免NullPointerException
s。
其他重要说明,主要来自评论:
this
在null
compareTo()
ComparisonChain
在实施Comparable
时,请务必指定type参数,以便您获得编译时类型安全,并且不必使用instanceof
或强制转换:
class Tok implements Comparable<Tok> {
// snip
public int compareTo(Tok other) {
// snip
}
}
答案 1 :(得分:5)
返回0意味着this
和o
相等,如果o
为空则不然。此外,this
永远不会为空。
当然,这取决于应用程序。您可能希望拥有一个等于null的对象。你返回的内容取决于你,但是如果你正在寻找一种通用的零安全方法,那么它并不是很理想。
要完全通用,我会检查o
是否为null
,如果是,则抛出某种异常。
答案 2 :(得分:4)
我对其他答案不满意:
你不应该在compareTo中检查null
要求它抛出NullPointerException,否则你会弄乱你的树,并且很难找到你的TreeMap无法工作的原因。
一种非常值得推荐的方法:
public int compareTo(Tok other) {
int thisRang = this.rang;
int otherRang = other.rang;
return (thisRang < otherRang ? -1 : (thisRang == otherRang ? 0 : 1));
}
public int compareTo(Object other) {
return compareTo((Tok)other);
}
进一步使其成为完美级别Tok应该是最终的! (否则你可能会有问题 当你从Tok继承。 (Sun在课堂日期发出错误)
final class Tok {
int rang;
}
处理compare和equals并不总是很容易,考虑使用HashMap代替Trees(TreeMap),然后你不必实现compareTo。 您应该实现hashCode,只需返回this.rang。
最后,它是高度推荐的,但并非强制要求实现equals()
public boolean equals(Object obj) {
return obj instanceof Tok
&& this.rang() == ((Tok) obj).rang;
}
答案 3 :(得分:1)
比较两个对象可以像任何其他方法一样安全,这里的问题是普通方法有两个参数,但compareTo
接收一个,另一个是对象本身。
this
永远不能为空,这意味着你在null
对象中执行代码(没有实例)。在这种情况下,NullPointerException
将在调用compareTo
时被抛出,从而无法执行其代码。
与对象一样多的方法,因为比较可以基于可以为null的类的字段(用于排除基元类型的目标)。因此,长话短说,您的空检查应该涵盖您作为compareTo
中的参数和使用的字段接收的对象。此外,如果您有一个包含某些逻辑的外部实例(即实用程序类),则应检查该实例是否也为空。
作为旁注,如果任何涉及的对象为null
,则返回的任何内容都必须一致并记录(您可以返回-1或1,在开头或结尾放置空值)。只是避免返回0(对于equals
对象,返回true
的情况与null
的情况相同。
答案 4 :(得分:1)
看似奇怪,但不安全。尝试将您的Tok添加到TreeSet或TreeMap(作为键),您将获得NullPointerException。问题是TreeSet的实现是基于TreeMap的。当您尝试添加(null)底层映射时,将尝试将您的null设置为导致NPE
答案 5 :(得分:1)
作者坚持认为他不想从他的中移除空值
托克[]。
这是一个允许使用NULL值排序的灵魂,并且不违反java契约
为避免这种情况,您在类内部Tok中创建了违反compareTo合约的, 你创建一个显式的NullSafeComparator:
/**
* This comparator accepts null objects,
* sorts ascending, null values are after non null values.
*/
public static final class NullSafeComparator implements Comparator<Tok> {
public int compare(Tok o1, Tok o2) {
int r1 = Integer.MAX_VALUE;
int r2 = Integer.MAX_VALUE;
if (o1 != null) {
r1 = o1.rang;
}
if (o2 != null) {
r2 = o2.rang;
}
return (r1 < r2 ? -1 : (r1 == r2 ? 0 : 1));
}
}
简化类Tok(删除静态关键字,用于定义一个单元测试类中的所有内容):
public static class Tok {
int rang;
public Tok(int rang) {
this.rang = rang;
}
public String toString() {
return Integer.toString(rang);
}
}
最后一个单元测试显示:
public void testSort() {
Tok[] toks = new Tok[5];
toks[0] = new Tok(3);
toks[1] = new Tok(1);
toks[2] = null;
toks[3] = null;
toks[4] = new Tok(2);
Arrays.sort(toks, new NullSafeComparator());
for (Tok tok: toks) {
System.out.println(tok);
}
assertEquals(1, toks[0]);
assertNull(toks[4]);
}
这将产生以下预期结果:
1
2
3
null
null
答案 6 :(得分:0)
Note that null is not an instance of any class, and e.compareTo(null) should
throw a NullPointerException even though e.equals(null) returns false.
因此,如果您实现了一个null-safe方法,它的行为将是意外的(也就是说文档不一致,并且可以与API的其余部分一致)。