Pergunta

Em Java, eu uso uma aula na qual alguns campos podem ser null. Por exemplo:

class Foo {
    String bar;
    //....
}

Eu quero escrever um barcomparador para esta aula,

    private static class BarComparator
            implements Comparator<Foo> {
        public int compare( final Foo o1, final Foo o2 )
        {
            // Implementation goes here
        }
    }

Existe uma maneira padrão de lidar com o fato de que qualquer um dos o1, o2, o1.bar, o2.bar pode ser null, sem escrever muito aninhado if...else?

Felicidades!

Foi útil?

Solução

Eu acho que você poderia envolver a chamada para o método compareto de campo com um pequeno método estático para classificar nulos altos ou baixos:

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

Uso simples (vários campos é como você faria):

public int compare( final Foo o1, final Foo o2 ) {
    return cp(o1.field, o2.field);
}

Outras dicas

Obrigado pelas respostas! O método genérico e os comparadores do Google parecem interessantes.

E eu descobri que há um NullComparator no Coleções do Apache Commons (que estamos usando atualmente):

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

Nota: Eu me concentrei no bar Campo aqui para mantê -lo direto.

Depende se você considera uma entrada nula como um valor de string válido que vale a pena comparar.é nulo < ou > "maçã".A única coisa que posso dizer com certeza é que null == null.Se você puder definir onde null se encaixa na ordem, poderá escrever o código adequadamente.

Nesse caso, eu poderia optar por lançar um NullPointerExcpetion ou IllegalArgumentException e tentar lidar com o nulo em um nível mais alto, não colocando-o na comparação em primeiro lugar.

Você pode escrever seu Comparador para isso.Digamos que você tenha uma classe Pessoa com nome String como campo privado.Método getName() e setName() para acessar o nome do campo.Abaixo está o Comparador para a classe 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());
        }
    });

Atualizar:

A partir do Java 8 você pode usar as APIs abaixo para List.

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

O principal aqui é descobrir como você gostaria que os nulos fossem tratados.Algumas opções são:a) assumir que os nulos vêm antes de todos os outros objetos na ordem de classificação b) assumir que os nulos vêm depois de todos os outros objetos na ordem de classificação c) tratar os nulos como equivalentes a algum valor padrão d) tratar os nulos como condições de erro.Qual você escolher dependerá inteiramente do aplicativo em que você está trabalhando.

No último caso, é claro, você lança uma exceção.Para os outros, você precisa de um caso if/else de quatro vias (cerca de três minutos de codificação em que você descobriu o que deseja que os resultados sejam).

Se você estiver usando as coleções do Google, poderá encontrar o Comparadores aula útil.If possui métodos auxiliares para ordenar nulos como os maiores ou menores elementos da coleção.Você pode usar comparadores compostos para ajudar a reduzir a quantidade de código.

Tem também a aula org.springframework.util.comparator.NullSafeComparator no Spring Framework você pode usar.

Exemplo (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 );

Isso imprimirá:

Foo{bar='null'}
Foo{bar='aaa'}
Foo{bar='zzz'}

Parece-me que não existe um método para fazer isso, mas de qualquer forma o código não é tão longo.

Você não deve usar o NullComparator da maneira que faz - você está criando uma nova instância da classe para cada operação de comparação e, se, por exemplo,você está classificando uma lista com 1.000 entradas, que serão 1.000 * log2(1000) objetos completamente supérfluos.Isso pode rapidamente se tornar problemático.

Subclasse-o, delegue-o ou simplesmente implemente sua própria verificação de nulos - na verdade não é tão complexo:

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

Considerando o Cliente como um POJO. Minha resposta seria:

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

Ou

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

Acho que declarações de retorno antecipadas seriam a outra alternativa para muitos ifs

por exemplo.

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.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top