我正在编写一些自定义比较器,我希望它们将空项目推送到列表的底部,无论我是按升序还是降序排序。接近这个的好策略或模式是什么?
Offhand:
还有其他策略吗?我想听听不同方法的经验,以及各种策略的任何陷阱。
答案 0 :(得分:11)
我同意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]
答案 1 :(得分:6)
最后一个选项对我很有吸引力。比较器非常适合链接在一起。特别是您可能希望编写ReverseComparator
以及NullWrappingComparator
。
编辑:详细说明我对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
。
答案 2 :(得分:5)
跟进dfa的回答 - 我想要的是nulls在最后排序而不影响非null的顺序。所以我想要更多的内容:
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);
}
};
}
}
但是对dfa完全赞同 - 这只是对他工作的一个小修改。
答案 3 :(得分:3)
在Java 8中,您可以使用Comparator.nullsLast
和Comparator.nullsFirst
静态方法来获得更多无效的比较器。假设您有一个Fruit
类,如下所示:
public class Fruit {
private final String name;
private final Integer size;
// Constructor and Getters
}
如果你想按照它们的大小对一堆水果进行排序,并将null
放在最后:
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]
答案 4 :(得分:2)
您总是可以使用来自commons-collections的NullComparator
。它比Google Collections长得多。