Java:空安全 compareTo 方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13517334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: null safe compareTo method
提问by Sterling Duchess
It has been asked before, but I have not found a decent implementation with an explanation.
之前有人问过,但我还没有找到一个像样的实现和解释。
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;
}
}
I read two similar questions that I found yet; they insist on implementing another method. I do not understand why this should not work. The method gets an extra object and it checks if its a valid instance or null
, if null
simply return 0
; what would be the easiest way to implement null-safe compareTo
.
我阅读了我发现的两个类似的问题;他们坚持实施另一种方法。我不明白为什么这不起作用。该方法获取一个额外的对象,并检查它是否是一个有效的实例,或者null
,如果null
只是返回0
;实现 null-safe 的最简单方法是什么compareTo
。
The implementation that worked for me was:
对我有用的实现是:
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;
}
}
It's not the optimal implementation one should look in to what good people posted here as answers. For my particular case this was decent enough as this is never null yet the object received can be null and the initial implementation states if either is null return 0. So if given object is null 0 is returned.
这不是最好的实现,人们应该查看这里发布的好人作为答案的内容。对于我的特殊情况,这已经足够了,因为它永远不会为空,但接收到的对象可以为空,并且初始实现状态是否为空返回 0。因此,如果给定的对象为空,则返回 0。
回答by Matt Ball
Personally, I like Guava's Ordering
for null-safe comparing. You can specify #nullsFirst()
or #nullsLast()
to avoid NullPointerException
s.
就个人而言,我喜欢Guava 的Ordering
null-safe 比较。您可以指定#nullsFirst()
或#nullsLast()
避免NullPointerException
s。
Other important notes, mostly from the comments:
其他重要说明,主要来自评论:
this
is nevernull
in Java- Consider using Guava's
ComparisonChain
if you're implementing a fine-grainedcompareTo()
When implementing
Comparable
, be sure to specify the type parameter so you get compile-time type safety and don't have to useinstanceof
or casts:class Tok implements Comparable<Tok> { // snip public int compareTo(Tok other) { // snip } }
this
是从来没有null
在Java中- 如果您要实现细粒度的,请考虑使用Guava
ComparisonChain
compareTo()
实现时
Comparable
,请务必指定类型参数,以便获得编译时类型安全,而不必使用instanceof
或强制转换:class Tok implements Comparable<Tok> { // snip public int compareTo(Tok other) { // snip } }
回答by EMMERICH
Returning 0 would imply that this
and o
are equal, which isn't true if o
is null. Also, this
will never be null.
返回 0 将意味着this
和o
相等,如果o
为空则不为真。此外,this
永远不会为空。
It's application-dependent, of course. You may want to have an object that should be equal to null. What you return there is up to you, but if you're looking for a general null safe method, it isn't really ideal.
当然,这取决于应用程序。您可能想要一个应该等于 null 的对象。你返回什么取决于你,但如果你正在寻找一个通用的空安全方法,它并不是很理想。
To be completely generic, I would check if o
is null
and, if so, throw some sort of Exception.
为了完全通用,我会检查是否o
是null
,如果是,则抛出某种异常。
回答by AlexWien
I am not satisified with the other answers:
You should NOT check for null in compareTo.
It is requested that it throws a NullPointerException, otheriwse you will mess up your Trees and have difficulties finding why your TreeMap does not work.
我对其他答案不满意:
您不应该在 compareTo 中检查 null。
要求它抛出一个 NullPointerException,否则你会弄乱你的树并且很难找到你的 TreeMap 不工作的原因。
A very recommendable method:
一个非常值得推荐的方法:
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);
}
Further to make it perfect class Tok should be final! (Otherwise you could have problems when you subclass from Tok. (Sun made that Error in Class Date)
进一步使它完美的类 Tok 应该是最终的!(否则当你从 Tok 继承时你可能会遇到问题。(Sun 在 Class Date 中犯了这个错误)
final class Tok {
int rang;
}
Dealing with compare and equals is not always easy, consider using instead of Trees (TreeMap) a HashMap, then you dont have to implement compareTo. You should implement hashCode, where you simply return this.rang.
处理 compare 和 equals 并不总是那么容易,考虑使用 HashMap 代替 Trees (TreeMap),然后就不必实现 compareTo。您应该实现 hashCode,您只需返回 this.rang。
Finally its is highly recomended, but not mandatory to implement equals()
最后它是强烈推荐的,但不是强制实现 equals()
public boolean equals(Object obj) {
return obj instanceof Tok
&& this.rang() == ((Tok) obj).rang;
}
回答by AlexWien
The author is insisting that he does not want to remove null values from his
Tok[].
Here is a soultion that allows to sort with NULL values, and is not violating java contracts
作者坚持认为他不想从他的 Tok[] 中删除空值。
这是一个允许使用 NULL 值进行排序的解决方案,并且不违反 Java 合同
To avoid that, you create a compareTo inside class Tok that violates the compareTo contract, you create an explicit NullSafeComparator:
为了避免这种情况,您在违反 compareTo 协定的 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));
}
}
simplified class Tok (remove the static keyword its is used to define that all inside one unit test class):
简化的类 Tok(删除 static 关键字,它用于在一个单元测试类中定义所有内容):
public static class Tok {
int rang;
public Tok(int rang) {
this.rang = rang;
}
public String toString() {
return Integer.toString(rang);
}
}
Finally a unit test to show:
最后一个单元测试显示:
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]);
}
Which will give the following desired result:
这将给出以下所需的结果:
1
2
3
null
null
回答by Fritz
Comparing two objects can be as null-safe as any other method, the catch here is that a normal method has two parameters but compareTo
receives one and the other one is the object itself.
比较两个对象可以像任何其他方法一样是空安全的,这里的问题是普通方法有两个参数但compareTo
接收一个参数,另一个是对象本身。
this
can NEVER be null, that would mean you're executing code in a null
object (no instance). In this case a NullPointerException
is going to be thrown right at the invocation of compareTo
, making impossible the execution of its code.
this
永远不能为空,这意味着您正在null
对象(无实例)中执行代码。在这种情况下, aNullPointerException
将在调用 时被抛出compareTo
,从而无法执行其代码。
There are as many approaches as objects, because a comparation can be based in the fields of a class that CAN be null (intended caps to exclude primitive types). So, long story short, your null checks should cover the object you receive as a parameter in compareTo
and the used fields. In addition, if you have an external instance that holds some logic (i.e. an utilities class) you should check if that instance is also null.
有与对象一样多的方法,因为比较可以基于可以为空的类的字段(旨在排除原始类型的大写字母)。因此,长话短说,您的空检查应该涵盖您作为参数接收的对象compareTo
和使用的字段。此外,如果您有一个包含某些逻辑的外部实例(即实用程序类),您应该检查该实例是否也为空。
As a side note, whatever you return if any involved object is null
must be consistent and documented (you can return -1 or 1, to place nulls at the beginning or at the end). Just avoid returning 0 (that would be the same case as if equals
returned true
for a null
object.
作为旁注,无论您返回任何涉及的对象,都null
必须一致并记录在案(您可以返回 -1 或 1,以在开头或结尾放置空值)。只是避免返回 0(这与为对象equals
返回的情况相同。true
null
回答by Evgeniy Dorofeev
Strange as it may seem but it is not safe. Try to add your Tok to TreeSet or TreeMap (as a key) and you will get a NullPointerException. The problem is that TreeSet imlementation is based on TreeMap. When you will try to add(null) underlying map will try to put your null which will result in NPE
看起来很奇怪,但它并不安全。尝试将您的 Tok 添加到 TreeSet 或 TreeMap(作为键),您将收到 NullPointerException。问题在于 TreeSet 的实现是基于 TreeMap 的。当您尝试添加(空)底层地图时,将尝试放置您的空值,这将导致 NPE
回答by kbec
According to the documentation:
根据文档:
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.
So if you implement a null-safe method, its behaviour will be unexpected (aka inconsitent with the documentation and propably with the rest of the API).
因此,如果您实现一个空安全方法,它的行为将是意外的(也就是与文档不一致,并且可能与 API 的其余部分不一致)。