对compare()中的空字段怎么办?
在Java中,我使用其中某些字段可以为null的类。例如:
class Foo { String bar; //.... }
我想为此类编写一个BarComparator,
private static class BarComparator implements Comparator<Foo> { public int compare( final Foo o1, final Foo o2 ) { // Implementation goes here } }
是否有一种标准的方法来处理以下事实:o1,o2,o1.bar,o2.bar中的任何一个都可以为null,而无需编写很多嵌套的if。还有吗?
干杯!
解决方案
在我看来,没有一种方法可以执行此操作,但是无论如何,代码并没有那么长。
我认为提前返回报表将是许多ifs的另一种选择
例如
if(o1==null) return x; if(o2==null) return x; if(o1.getBar()==null) return x; if(o2.getBar()==null) return x; // No null checks needed from this point.
这取决于我们是否将空条目视为值得比较的有效字符串值。为null <或者>" apple"。我唯一可以肯定地说的是null == null。如果我们可以定义null在排序中的位置,则可以适当地编写代码。
在这种情况下,我可能选择抛出NullPointerExcpetion或者IllegalArgumentException并尝试通过不首先将其放在比较中的方式来在更高级别上处理null。
我猜你可以用一个小的静态方法包装对字段compareTo方法的调用,以对null进行高低排序:
static <T extends Comparable<T>> int cp(T a, T b) { return a==null ? (b==null ? 0 : Integer.MIN_VALUE) : (b==null ? Integer.MAX_VALUE : a.compareTo(b)); }
使用简单(我们通常会使用多个字段):
public int compare( final Foo o1, final Foo o2 ) { return cp(o1.field, o2.field); }
这里的关键是弄清楚我们希望如何处理空值。一些选项是:a)假定null排在所有其他对象之前,按排序顺序b)假定null在排在所有其他对象之后,按照排序顺序c)将null视为等同于某些默认值d)将null视为错误条件我们选择哪一个将完全取决于我们正在处理的应用程序。
当然,在最后一种情况下,我们将引发异常。对于其他情况,我们需要四路if / else情况(大约编码三分钟即可得出想要的结果)。
如果我们使用的是Google收藏夹,则Comparators类可能会有所帮助。 If具有将空值排序为集合中最大或者最小元素的辅助方法。我们可以使用复合比较器来帮助减少代码量。
感谢答复!通用方法和Google比较器看起来很有趣。
我发现在Apache Commons Collections(我们当前正在使用)中有一个NullComparator:
private static class BarComparator implements Comparator<Foo> { public int compare( final Foo o1, final Foo o2 ) { // o1.bar & o2.bar nulleness is taken care of by the NullComparator. // Easy to extend to more fields. return NULL_COMPARATOR.compare(o1.bar, o2.bar); } private final static NullComparator NULL_COMPARATOR = new NullComparator(false); }
注意:在这里,我专注于"酒吧"领域,以保持重点。
我们不应以为每个比较操作创建类的新实例的方式使用NullComparator,例如我们正在对包含1000个条目的列表进行排序,这将是1000 * log2(1000)个完全多余的对象。这很快就会出现问题。
它的子类,或者委托它,或者简单地实现自己的null检查,它实际上并不那么复杂:
private static class BarComparator implements Comparator<Foo> { private NullComparator delegate = new NullComparator(false); public int compare( final Foo o1, final Foo o2 ) { return delegate.compare(o1.bar, o2.bar); } }