无论如何,将空值排序到底部的一般方法很好吗?

Car*_*ter 8 java design-patterns comparator

我正在编写一些自定义比较器,我希望它们将空项目推送到列表的底部,无论我是按升序还是降序排序.接近这个的好策略或模式是什么?

随口说说:

  • 只需编写单独的升序和降序比较器,尽可能共享代码
  • 通过抛出NPE或通过显式调用来将null处理委托给另一个类
  • 包含一个升序标志并在其中放置条件逻辑以导航空值
  • 在null处理类中包装常规比较器

还有其他策略吗?我想听听有关不同方法的任何经验,以及各种策略的任何陷阱.

dfa*_*dfa 11

我同意Jon Skeet(这很容易:).我试图实现一个非常简单的装饰器:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

鉴于比较者:

Comparator<String> wrapMe = new Comparator<String>() {
      public int compare(String o1, String o2) {
          return o1.compareTo(o2);
      }
};
Run Code Online (Sandbox Code Playgroud)

和一些测试数据:

List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null);
Run Code Online (Sandbox Code Playgroud)

您可以在结尾处使用空值排序:

Collections.sort(strings, NullComparators.atEnd(wrapMe));
Run Code Online (Sandbox Code Playgroud)
[aaa, bbb, ccc, null, null, null]

或者在开始时:

Collections.sort(strings, NullComparators.atBeginning(wrapMe));
Run Code Online (Sandbox Code Playgroud)
[null, null, null, ccc, bbb, aaa]

  • 非常好!谢谢.如果两个参数都为null,是否有理由不返回0?我知道null行为不像非null行为,并且说两个空值相等是值得怀疑的 - 但是说一个超过另一个是不是有问题吗? (3认同)
  • @Carl:我刚才对你的帖子做了点:)比较器*应该*返回0或者在传递两个空值时抛出异常,否则它违反了接口契约. (2认同)

Jon*_*eet 6

最后一个选项对我很有吸引力.比较器非常适合链接在一起.特别是你可能想要写一个ReverseComparator以及一个NullWrappingComparator.


编辑:你不必自己写.如果您查看Google Collections Library中的Ordering类,您会发现这个以及各种其他好东西:)


编辑:进入更多细节,以显示我的意思ReverseComparator...

一个警告 - 在执行a时ReverseComparator,反转参数的顺序而不是否定结果,否则Integer.MIN_VALUE将"逆转"到自身.

所以这个实现是错误的(假设original是比较器反转):

public int compare(T x, T y)
{
    return -original.compare(x, y);
}
Run Code Online (Sandbox Code Playgroud)

但这是对的:

public int compare(T x, T y)
{
    return original.compare(y, x);
}
Run Code Online (Sandbox Code Playgroud)

原因是我们总是想要反转比较,但如果original.compare(x, y)返回int.MIN_VALUE,那么坏的比较器将返回int.MIN_VALUE,这是不正确的.这是由于有趣的财产int.MIN_VALUE == -int.MIN_VALUE.


Car*_*ter 5

继续讨论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);
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

尽管如此,这完全归功于dfa - 这只是对他作品的一个小修改.


Ali*_*ani 5

在 Java 8 中,您可以使用 theComparator.nullsLastComparator.nullsFirststatic 方法来拥有更多对 null 友好的比较器。假设您有一个Fruit如下所示的类:

public class Fruit {
    private final String name;
    private final Integer size;

    // Constructor and Getters
}
Run Code Online (Sandbox Code Playgroud)

如果您想按大小对一堆水果进行排序并将nulls 放在末尾:

List<Fruit> fruits = asList(null, new Fruit("Orange", 25), new Fruit("Kiwi", 5));
Run Code Online (Sandbox Code Playgroud)

你可以简单地写:

Collections.sort(fruits, Comparator.nullsLast(Comparator.comparingInt(Fruit::getSize)));
Run Code Online (Sandbox Code Playgroud)

结果将是:

[Fruit{name='Kiwi', size=5}, Fruit{name='Orange', size=25}, null]
Run Code Online (Sandbox Code Playgroud)