我正在写一些自定义比较器,并且我希望他们将空项目推送到列表底部,而不管我是按升序还是降序排序。接近这个的好策略或模式是什么?不管一般的方法将空值排序到底部?
随口说说:
- 只需编写单独的上升和 下降比较,共享代码 在可能的情况
- 代表空处理另一个 类,无论是通过调用它明确 抛出NPE或
- 包含一个升序标志,并在其中放置 条件逻辑以在空值周围导航
- 将常规比较器包装在 空处理类
任何其他策略?我想听听任何不同方法的经验,以及各种策略的任何陷阱。
我正在写一些自定义比较器,并且我希望他们将空项目推送到列表底部,而不管我是按升序还是降序排序。接近这个的好策略或模式是什么?不管一般的方法将空值排序到底部?
随口说说:
任何其他策略?我想听听任何不同方法的经验,以及各种策略的任何陷阱。
最后一个选项对我很有吸引力。比较器真的很好链接在一起。特别是你可能想写一个ReverseComparator
以及一个NullWrappingComparator
。
编辑:你不必自己写这个。如果你看一下在Google Collections Library的Ordering类,你会发现这和其他各种好吃的东西:)
编辑:走进更详细地说明我的意思大约ReverseComparator
...
一个警告字 - 在执行ReverseComparator
时,颠倒参数的顺序而不是否定结果,否则Integer.MIN_VALUE
会自动反转。
所以这个实现是错误的(假设original
是扭转比较):
public int compare(T x, T y)
{
return -original.compare(x, y);
}
但这是正确的:
public int compare(T x, T y)
{
return original.compare(y, x);
}
的原因是,我们总是希望扭转相比,但如果original.compare(x, y)
返回int.MIN_VALUE
,那么坏比较器将也返回int.MIN_VALUE
,这是不正确的。这是由于有趣的属性,int.MIN_VALUE == -int.MIN_VALUE
。
我同意Jon Skeet(这很容易:)。我试图实现一个非常简单的decorator:
class NullComparators {
static <T> Comparator<T> atEnd(final Comparator<T> comparator) {
return new Comparator<T>() {
public int compare(T o1, T o2) {
if (o1 == null && o2 == null) {
return 0;
}
if (o1 == null) {
return 1;
}
if (o2 == null) {
return -1;
}
return comparator.compare(o1, o2);
}
};
}
static <T> Comparator<T> atBeginning(final Comparator<T> comparator) {
return Collections.reverseOrder(atEnd(comparator));
}
}
给出一个比较:
Comparator<String> wrapMe = new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
和一些测试数据:
:List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null);
你可以在结束与空值进行排序
Collections.sort(strings, NullComparators.atEnd(wrapMe));
[aaa, bbb, ccc, null, null, null]
或开头:
Collections.sort(strings, NullComparators.atBeginning(wrapMe));
[null, null, null, ccc, bbb, aaa]
非常好!谢谢。如果两个参数都为空,是否有返回0的理由?我知道空行为不像非空行为,并且说两个空值是相等的是值得怀疑的 - 但是说一个超过另一个是否可疑? – 2009-08-11 18:36:56
@Carl:准确地说,我刚刚对你的帖子提出了一点要求:) Comparator *应该返回0,或者在传递两个空值时抛出异常,否则它将违反接口合约。 – 2009-08-11 19:20:07
DFA的回答跟进 - 我想要的是,零点排序在不影响非空的顺序结束。所以,我想要的东西沿着这个线路更多:到DFA
public class NullComparatorsTest extends TestCase {
Comparator<String> forward = new Comparator<String>() {
public int compare(String a, String b) {
return a.compareTo(b);
}
};
public void testIt() throws Exception {
List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null);
Collections.sort(strings, NullComparators.atEnd(forward));
assertEquals("[aaa, bbb, ccc, null, null, null]", strings.toString());
Collections.sort(strings, NullComparators.atBeginning(forward));
assertEquals("[null, null, null, aaa, bbb, ccc]", strings.toString());
}
}
public class NullComparators {
public static <T> Comparator<T> atEnd(final Comparator<T> comparator) {
return new Comparator<T>() {
public int compare(T a, T b) {
if (a == null && b == null)
return 0;
if (a == null)
return 1;
if (b == null)
return -1;
return comparator.compare(a, b);
}
};
}
public static <T> Comparator<T> atBeginning(final Comparator<T> comparator) {
return new Comparator<T>() {
public int compare(T a, T b) {
if (a == null && b == null)
return 0;
if (a == null)
return -1;
if (b == null)
return 1;
return comparator.compare(a, b);
}
};
}
}
完全学分制,虽然 - 这是他的工作只是一个小的修改。
一个问题:比较两个空值时不返回0。 – 2009-08-11 19:18:45
谢谢;进行更正编辑。 – 2009-08-11 21:02:35
您可以随时使用commons-collections的NullComparator
。它的历史比Google Collections更长。
在Java 8中,可以使用Comparator.nullsLast
和Comparator.nullsFirst
静态方法来使用更多的无空值比较器。假设你有一个Fruit
类像下面这样:
public class Fruit {
private final String name;
private final Integer size;
// Constructor and Getters
}
如果要排序一堆水果通过它们的大小,并把null
s的结尾:
List<Fruit> fruits = asList(null, new Fruit("Orange", 25), new Fruit("Kiwi", 5));
你可以简单的写:
Collections.sort(fruits, Comparator.nullsLast(Comparator.comparingInt(Fruit::getSize)));
其结果将是:
[Fruit{name='Kiwi', size=5}, Fruit{name='Orange', size=25}, null]
我同意你的所有答案,除非否定比较结果;如果我发现比较器使用减法实现整数比较,那么我会相当不高兴,因为该方法有很多缺陷。 – jprete 2009-08-11 19:08:13
@jprete:我想你误解了我。我会编辑。 – 2009-08-11 19:13:39
由于参考Google集合的订购类,我接受此答案 - 现有经过验证的代码是最佳解决方案。还针对有关Integer.MIN_VALUE的警告。但是我非常感谢@dfa的代码,并希望我能接受这两个答案。 – 2009-08-11 23:05:46