Question

En Java, j'utilise une classe dans laquelle certains champs peuvent être null . Par exemple:

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

Je veux écrire un BarComparator pour cette classe,

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

Existe-t-il un moyen standard de traiter le fait que o1 , o2 , o1.bar , o2. La barre peut être null , sans écrire beaucoup de imbriqué si ... sinon ?

Salut!

Était-ce utile?

La solution

Je suppose que vous pouvez encapsuler l'appel de la méthode compareTo sur le terrain avec une petite méthode statique pour trier les valeurs NULL en haut ou en bas:

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

Utilisation simple (plusieurs champs sont comme d'habitude):

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

Autres conseils

Merci pour les réponses! La méthode générique et les comparateurs Google semblent intéressants.

Et j’ai trouvé qu’il existait un NullComparator dans les Collections Apache Commons (que nous sommes utilise actuellement):

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

Remarque: je me suis concentré sur le champ barre ici pour le garder au point.

Cela dépend si vous considérez une entrée NULL comme une valeur de chaîne valide pouvant être comparée. est null < ou > "pomme". La seule chose que je puisse dire avec certitude est que null == null. Si vous pouvez définir l'emplacement de null dans l'ordre, vous pouvez écrire le code de manière appropriée.

Dans ce cas, je pourrais choisir de lancer une exception NullPointerExcpetion ou IllegalArgumentException et d'essayer de gérer le null à un niveau supérieur en ne le plaçant pas dans la comparaison.

Vous pouvez écrire votre comparateur pour cela. Disons que vous avez une classe Person avec un nom de chaîne comme champ privé. getName () et setName () pour accéder au nom du champ. Vous trouverez ci-dessous le comparateur de la 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());
        }
    });

Mise à jour:

À partir de Java 8, vous pouvez utiliser les API ci-dessous pour la liste.

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

L'important est de déterminer comment vous souhaitez que les valeurs NULL soient traitées. Certaines options sont les suivantes: a) supposer que les valeurs null viennent avant tous les autres objets dans l'ordre de tri b) supposer que les valeurs null viennent après tous les autres objets dans l'ordre de tri c) traiter la valeur null comme équivalent à une valeur par défaut d) traiter les valeurs null comme des conditions d'erreur. Laquelle que vous choisirez dépendra entièrement de l’application sur laquelle vous travaillez.

Dans le dernier cas, bien sûr, vous lancez une exception. Pour les autres, vous avez besoin d’un cas à quatre voies si / d’autre (environ trois minutes de codage pour un cas, vous avez déterminé les résultats souhaités).

Si vous utilisez des collections Google, vous pouvez trouver le fichier Comparateurs de classe utile. If dispose de méthodes d'assistance pour classer les valeurs NULL en tant qu'éléments les plus importants ou les moins importants de la collection. Vous pouvez utiliser comparateurs composés pour aider à réduire la quantité de code.

Vous pouvez également utiliser la classe org.springframework.util.comparator.NullSafeComparator dans Spring Framework.

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

Ceci imprimera:

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

Il me semble qu'il n'y a pas de méthode pour le faire, mais de toute façon le code n'est pas si long.

Vous ne devez pas utiliser NullComparator comme vous le faites - vous créez une nouvelle instance de la classe pour chaque opération de comparaison, et si par exemple. vous triez une liste de 1 000 entrées, ce qui donnera 1 000 * log2 (1 000) objets complètement superflus. Cela peut rapidement devenir problématique.

Vous pouvez soit le sous-classer, soit y déléguer, soit simplement mettre en œuvre votre propre contrôle null - ce n'est vraiment pas si complexe:

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

Considérer le client comme un POJO.Ma réponse serait:

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

Ou

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

Je pense que les déclarations de retour anticipées seraient l’autre alternative à beaucoup de ifs

par exemple

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.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top