Вопрос

В 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...else?

Ваше здоровье!

Это было полезно?

Решение

Я думаю, вы могли бы обернуть вызов метода field compareTo небольшим статическим методом для сортировки значений null high или low:

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

Другие советы

Спасибо за ответы!Универсальный метод и компараторы Google выглядят интересными.

И я обнаружил, что есть Нулевой параметр в Коллекции Apache Commons (который мы сейчас используем):

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 укажите здесь, чтобы не переходить к сути.

Это зависит от того, считаете ли вы нулевую запись допустимым строковым значением, заслуживающим сравнения.равно нулю < или > "яблоко".Единственное, что я мог бы сказать наверняка, это то, что null == null.Если вы можете определить, где null вписывается в порядок, то вы можете написать код соответствующим образом.

В этом случае я мог бы выбрать исключение NullPointerExcpetion или IllegalArgumentException и попытаться обработать значение null на более высоком уровне, не помещая его в сравнение в первую очередь.

Вы можете написать для него свой компаратор.Допустим, у вас есть класс Person со строковым именем в качестве закрытого поля.Методы getName() и setName() для доступа к имени поля.Ниже приведен компаратор для класса 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());
        }
    });

Обновить:

Начиная с Java 8, вы можете использовать приведенные ниже 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));

Ключевым моментом здесь является определение того, как бы вы хотели, чтобы нулевые значения обрабатывались.Вот некоторые варианты:a) предположим, что нули появляются перед всеми другими объектами в порядке сортировки b) предположим, что нули появляются после всех других объектов в порядке сортировки c) рассматривайте null как эквивалент некоторого значения по умолчанию d) рассматривайте null как условия ошибки.Какой из них вы выберете, будет полностью зависеть от приложения, над которым вы работаете.

В последнем случае, конечно, вы создаете исключение.Для остальных вам нужен четырехсторонний вариант if / else (примерно за три минуты кодирования вы определили, какими должны быть результаты).

Если вы используете Google Collections, вы можете найти Компараторы полезное занятие.If имеет вспомогательные методы для упорядочивания нулей как наибольших, так и наименьших элементов в коллекции.Вы можете использовать составные компараторы чтобы помочь уменьшить объем кода.

Существует также класс org.springframework.util.comparator.NullSafeComparator в Spring Framework вы можете использовать.

Пример (Java 8):

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'}

Мне кажется, что нет способа сделать это, но в любом случае код не такой длинный.

Вам не следует использовать 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);
    }
}

Рассматривая клиента как POJO.Мой ответ был бы :

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

Или

Comparator<Customer> compareByName = Comparator.comparing(Customer::getName,nullsLast(String::compareTo));

Я думаю, что заявления о досрочном возврате были бы другой альтернативой множеству "если"

например ,

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.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top