代码之家  ›  专栏  ›  技术社区  ›  Sébastien RoccaSerra

如何处理compare()中的空字段?

  •  21
  • Sébastien RoccaSerra  · 技术社区  · 18 年前

    在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 无效的 ,没有写很多嵌套的 if ... else ?

    干杯

    11 回复  |  直到 18 年前
        1
  •  37
  •   Jared Burrows    11 年前

    我想您可以使用一个小的静态方法将对字段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);
    }
    
        2
  •  8
  •   Sébastien RoccaSerra    18 年前

    谢谢你的回复!通用方法和谷歌比较器看起来很有趣。

    NullComparator 在 Apache Commons Collections (我们目前正在使用):

    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);
    }
    

    bar 在这里输入一个字段,以使其切中要害。

        3
  •  6
  •   Matt    18 年前

    这取决于您是否考虑空项是一个值得比较的有效字符串值。为空<或>“苹果”。我唯一可以肯定的是null==null。如果您可以定义null在排序中的位置,那么您可以适当地编写代码。

    在这种情况下,我可能会选择抛出一个NullPointerException或IllegalArgumentException,并尝试在更高级别上处理null,方法是首先不将其放在比较中。

        4
  •  3
  •   DJClayworth    18 年前

    这里的关键问题是确定如何处理null。有些选项是:a)假设null位于排序顺序中的所有其他对象之前b)假设null位于排序顺序中的所有其他对象之后c)将null视为等同于某些默认值d)将null视为错误条件。您选择哪一个将完全取决于您正在使用的应用程序。

    当然,在最后一种情况下,您会抛出一个异常。对于其他情况,您需要一个四向if/else案例(大约三分钟的编码时间,您已经计算出您想要的结果)。

        5
  •  3
  •   Gregg    18 年前

    如果您使用的是Google collections,您可能会发现 Comparators 上课很有帮助。If具有用于将null排序为集合中最大或最小元素的帮助器方法。你可以用 compound comparators

        6
  •  3
  •   Wim Deblauwe    10 年前

    还有这个班 org.springframework.util.comparator.NullSafeComparator 在Spring框架中,您可以使用。

    SortedSet<Foo> foos = new TreeSet<>( ( o1, o2 ) -> {
            return new NullSafeComparator<>( String::compareTo, true ).compare( o1.getBar(), o2.getBar() );
        } );
    
        foos.add( new Foo(null) );
        foos.add( new Foo("zzz") );
        foos.add( new Foo("aaa") );
    
        foos.stream().forEach( System.out::println );
    

    这将打印:

    Foo{bar='null'}
    Foo{bar='aaa'}
    Foo{bar='zzz'}
    
        7
  •  3
  •   savanibharat    9 年前

    您可以为它编写比较器。假设您有一个字符串名为private字段的类Person。方法来访问字段名。下面是班级人员的比较表。

        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person a, Person b) {
                if (a == null) {
                    if (b == null) {
                        return 0;
                    }
                    return -1;
                } else if (b == null) {
                    return 1;
                }
                return a.getName().compareTo(b.getName());
            }
        });
    

    从Java8开始,您可以使用下面的API作为列表。

    // Push nulls at the end of List
    Collections.sort(subjects1, Comparator.nullsLast(String::compareTo));
    
    // Push nulls at the beginning of List
    Collections.sort(subjects1, Comparator.nullsFirst(String::compareTo));
    
        8
  •  2
  •   Mr.Koçak    8 年前

    将客户视为POJO。我的答案是:

    Comparator<Customer> compareCustomer = Comparator.nullsLast((c1,c2) -> c1.getCustomerId().compareTo(c2.getCustomerId()));
    

    或

    Comparator<Customer> compareByName = Comparator.comparing(Customer::getName,nullsLast(String::compareTo));
    
        9
  •  1
  •   Martin Probst    18 年前

    您不应该像使用NullComparator那样使用它-您正在为每个比较操作创建一个新的类实例,例如,如果您正在对一个包含1000个条目的列表进行排序,那么这将是1000*log2(1000)个完全多余的对象。这很快就会产生问题。

    要么将其子类化,要么将其委托给它,要么只是实现自己的空检查——其实并没有那么复杂:

    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);
        }
    }
    
        10
  •  0
  •   cagcowboy    18 年前

    我认为早期返回声明将是许多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.