Wie vereinfache ich eine null-sichere compareTo () - Implementierung?

156

Ich implementiere eine compareTo()Methode für eine einfache Klasse wie diese (um Collections.sort()andere von der Java-Plattform angebotene Extras verwenden zu können ):

public class Metadata implements Comparable<Metadata> {
    private String name;
    private String value;

// Imagine basic constructor and accessors here
// Irrelevant parts omitted
}

Ich möchte, dass die natürliche Reihenfolge für diese Objekte wie folgt lautet: 1) sortiert nach Namen und 2) sortiert nach Wert, wenn der Name derselbe ist; Bei beiden Vergleichen sollte die Groß- und Kleinschreibung nicht berücksichtigt werden. Für beide Felder sind Nullwerte durchaus akzeptabel und compareTodürfen in diesen Fällen nicht unterbrochen werden.

Die Lösung, die mir in den Sinn kommt, sieht wie folgt aus (ich verwende hier "Schutzklauseln", während andere vielleicht einen einzelnen Rückgabepunkt bevorzugen, aber das ist nebensächlich):

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(Metadata other) {
    if (this.name == null && other.name != null){
        return -1;
    }
    else if (this.name != null && other.name == null){
        return 1;
    }
    else if (this.name != null && other.name != null) {
        int result = this.name.compareToIgnoreCase(other.name);
        if (result != 0){
            return result;
        }
    }

    if (this.value == null) {
        return other.value == null ? 0 : -1;
    }
    if (other.value == null){
        return 1;
    }

    return this.value.compareToIgnoreCase(other.value);
}

Das macht den Job, aber ich bin mit diesem Code nicht ganz zufrieden. Zugegeben, es ist nicht sehr komplex, aber ziemlich ausführlich und langweilig.

Die Frage ist, wie würden Sie dies weniger ausführlich machen (unter Beibehaltung der Funktionalität)? Sie können sich gerne auf Java-Standardbibliotheken oder Apache Commons beziehen, wenn diese helfen. Wäre die einzige Möglichkeit, dies (ein wenig) einfacher zu machen, die Implementierung meines eigenen "NullSafeStringComparator" und dessen Anwendung zum Vergleich beider Felder?

Änderungen 1-3 : Eddie hat recht; Der obige Fall "beide Namen sind null" wurde behoben

Über die akzeptierte Antwort

Ich habe diese Frage bereits 2009 gestellt, natürlich auf Java 1.6, und zu der Zeit war die reine JDK-Lösung von Eddie meine bevorzugte akzeptierte Antwort. Ich bin bis jetzt (2017) nie dazu gekommen, das zu ändern.

Es gibt auch Bibliothekslösungen von Drittanbietern - eine Apache Commons Collections 2009 und eine Guava 2013, die beide von mir veröffentlicht wurden -, die ich zu einem bestimmten Zeitpunkt bevorzugt habe.

Ich habe jetzt die saubere Java 8-Lösung von Lukasz Wiktor zur akzeptierten Antwort gemacht. Dies sollte auf jeden Fall unter Java 8 bevorzugt werden, und heutzutage sollte Java 8 für fast alle Projekte verfügbar sein.

Jonik
quelle
stackoverflow.com/questions/369383/…
Ciro Santilli 法轮功 冠状 冠状. 六四

Antworten:

173

Verwenden von Java 8 :

private static Comparator<String> nullSafeStringComparator = Comparator
        .nullsFirst(String::compareToIgnoreCase); 

private static Comparator<Metadata> metadataComparator = Comparator
        .comparing(Metadata::getName, nullSafeStringComparator)
        .thenComparing(Metadata::getValue, nullSafeStringComparator);

public int compareTo(Metadata that) {
    return metadataComparator.compare(this, that);
}
Lukasz Wiktor
quelle
7
Ich unterstütze die Verwendung von Java 8-integriertem Material zugunsten von Apache Commons Lang, aber dieser Java 8-Code ist ziemlich hässlich und immer noch ausführlich. Ich werde mich vorerst an org.apache.commons.lang3.builder.CompareToBuilder halten.
Jschreiner
1
Dies funktioniert nicht für Collections.sort (Arrays.asList (null, val1, null, val2, null)), da versucht wird, compareTo () für ein Null-Objekt aufzurufen. Um ehrlich zu sein, scheint es ein Problem mit dem Sammlungs-Framework zu sein, herauszufinden, wie man dies in die Enge treibt.
Pedro Borges
3
@PedroBorges Der Autor fragte nach dem Sortieren von Containerobjekten mit sortierbaren Feldern (wobei diese Felder möglicherweise null sind) und nicht nach dem Sortieren von Nullcontainerreferenzen. Während Ihr Kommentar korrekt ist, Collections.sort(List)funktioniert dies nicht, wenn die Liste Nullen enthält. Der Kommentar ist jedoch für die Frage nicht relevant.
Scrubbie
211

Sie können einfach Apache Commons Lang verwenden :

result = ObjectUtils.compare(firstComparable, secondComparable)
Dag
quelle
4
(@Kong: Dies sorgt für Null-Sicherheit, aber nicht für Groß- und Kleinschreibung, was ein weiterer Aspekt der ursprünglichen Frage war. Dadurch wird die akzeptierte Antwort nicht
geändert
3
Meiner Meinung nach sollte Apache Commons 2013 nicht die akzeptierte Antwort sein. (Auch wenn einige Teilprojekte besser gepflegt werden als andere.) Guave kann verwendet werden, um dasselbe zu erreichen . siehe nullsFirst()/ nullsLast().
Jonik
8
@ Jonik Warum sollte Apache Commons Ihrer Meinung nach 2013 nicht die akzeptierte Antwort sein?
wirklich schön
1
Große Teile von Apache Commons sind Legacy- / schlecht gewartete / minderwertige Produkte. Es gibt bessere Alternativen für die meisten Dinge, die es bietet, zum Beispiel in Guava, das durchweg eine sehr hochwertige Bibliothek ist, und zunehmend in JDK selbst. Um 2005 ja, Apache Commons war die Scheiße, aber heutzutage besteht in den meisten Projekten keine Notwendigkeit dafür. (Sicher, es gibt Ausnahmen; wenn ich zum Beispiel aus irgendeinem Grund einen FTP-Client benötige, würde ich wahrscheinlich den in Apache Commons Net usw. verwenden.)
Jonik
6
@ Jonik, wie würdest du die Frage mit Guava beantworten? Ihre Behauptung, dass Apache Commons Lang (Paket org.apache.commons.lang3) "Legacy / schlecht gewartet / von geringer Qualität" ist, ist falsch oder bestenfalls unbegründet. Commons Lang3 ist leicht zu verstehen und zu verwenden und wird aktiv gewartet. Es ist wahrscheinlich meine am häufigsten verwendete Bibliothek (abgesehen von Spring Framework und Spring Security) - die StringUtils- Klasse mit ihren null-sicheren Methoden macht beispielsweise die Normalisierung von Eingaben trivial.
Paul
93

Ich würde einen null sicheren Komparator implementieren. Es mag eine Implementierung geben, aber diese ist so einfach zu implementieren, dass ich immer meine eigene gerollt habe.

Hinweis: Wenn beide Namen null sind, vergleicht Ihr Komparator oben nicht einmal die Wertefelder. Ich glaube nicht, dass du das willst.

Ich würde dies mit so etwas wie dem folgenden implementieren:

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(final Metadata other) {

    if (other == null) {
        throw new NullPointerException();
    }

    int result = nullSafeStringComparator(this.name, other.name);
    if (result != 0) {
        return result;
    }

    return nullSafeStringComparator(this.value, other.value);
}

public static int nullSafeStringComparator(final String one, final String two) {
    if (one == null ^ two == null) {
        return (one == null) ? -1 : 1;
    }

    if (one == null && two == null) {
        return 0;
    }

    return one.compareToIgnoreCase(two);
}

BEARBEITEN: Tippfehler im Codebeispiel behoben. Das bekomme ich, wenn ich es nicht zuerst teste!

BEARBEITEN: nullSafeStringComparator wurde auf statisch hochgestuft.

Eddie
quelle
2
In Bezug auf verschachteltes "Wenn" ... finde ich das verschachtelte Wenn für diesen Fall weniger lesbar, daher vermeide ich es. Ja, manchmal kommt es deshalb zu einem unnötigen Vergleich. final für Parameter ist nicht erforderlich, aber eine gute Idee.
Eddie
31
Süße Verwendung von XOR
James McMahon
9
@phihag - Ich weiß, dass es über 3 Jahre sind, ABER ... das finalSchlüsselwort ist nicht wirklich notwendig (Java-Code ist bereits so ausführlich wie er ist). Es verhindert jedoch die Wiederverwendung von Parametern als lokale Variablen (eine schreckliche Codierungspraxis.) As Unser kollektives Verständnis von Software wird mit der Zeit besser. Wir wissen, dass die Dinge standardmäßig endgültig / const / unveränderlich sein sollten. Daher bevorzuge ich ein bisschen mehr Ausführlichkeit bei der Verwendung finalin Parameterdeklarationen (wie trivial die Funktion auch sein mag), um sie zu erhalten inmutability-by-quasi-default.) Der Aufwand für Verständlichkeit / Wartbarkeit ist im großen Schema der Dinge vernachlässigbar.
Luis.espinal
24
@ James McMahon Ich muss nicht zustimmen. Xor (^) könnte einfach durch ungleich (! =) Ersetzt werden. Es wird sogar mit demselben Bytecode kompiliert. Die Verwendung von! = Vs ^ ist nur eine Frage des Geschmacks und der Lesbarkeit. Nach der Tatsache zu urteilen, dass Sie überrascht waren, würde ich sagen, dass es nicht hierher gehört. Verwenden Sie xor, wenn Sie versuchen, eine Prüfsumme zu berechnen. In den meisten anderen Fällen (wie diesem) bleiben wir bei! =.
Bvdb
5
Es ist einfach, diese Antwort zu erweitern, indem String durch T ersetzt wird, T deklariert als <T erweitert Comparable <T>> ... und dann können wir alle nullbaren Comparable-Objekte sicher vergleichen
Thierry
20

Unten in dieser Antwort finden Sie eine aktualisierte (2013) Lösung mit Guava.


Damit bin ich letztendlich gegangen. Es stellte sich heraus, dass wir bereits eine Dienstprogrammmethode für den nullsicheren String-Vergleich hatten. Die einfachste Lösung bestand darin, diese zu nutzen. (Es ist eine große Codebasis; leicht zu übersehen :)

public int compareTo(Metadata other) {
    int result = StringUtils.compare(this.getName(), other.getName(), true);
    if (result != 0) {
        return result;
    }
    return StringUtils.compare(this.getValue(), other.getValue(), true);
}

So wird der Helfer definiert (er ist überladen, sodass Sie auch definieren können, ob Nullen zuerst oder zuletzt kommen, wenn Sie möchten):

public static int compare(String s1, String s2, boolean ignoreCase) { ... }

Dies ist also im Wesentlichen dasselbe wie Eddies Antwort (obwohl ich eine statische Hilfsmethode nicht als Komparator bezeichnen würde ) und die von Uzhin .

Im Allgemeinen hätte ich Patricks Lösung nachdrücklich favorisiert , da ich denke, dass es eine gute Praxis ist, etablierte Bibliotheken zu verwenden, wann immer dies möglich ist. ( Kennen und verwenden Sie die Bibliotheken, wie Josh Bloch sagt.) In diesem Fall hätte dies jedoch nicht den saubersten und einfachsten Code ergeben.

Edit (2009): Apache Commons Collections-Version

Hier ist eine Möglichkeit, die auf Apache Commons basierende Lösung zu NullComparatorvereinfachen. Kombinieren Sie es mit der in der Klasse angegebenen Groß- und KleinschreibungComparatorString :

public static final Comparator<String> NULL_SAFE_COMPARATOR 
    = new NullComparator(String.CASE_INSENSITIVE_ORDER);

@Override
public int compareTo(Metadata other) {
    int result = NULL_SAFE_COMPARATOR.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return NULL_SAFE_COMPARATOR.compare(this.value, other.value);
}

Das ist ziemlich elegant, denke ich. (Es bleibt nur ein kleines Problem: Die Commons NullComparatorunterstützen keine Generika, daher gibt es eine ungeprüfte Zuordnung.)

Update (2013): Guava-Version

Fast 5 Jahre später würde ich meine ursprüngliche Frage folgendermaßen angehen. Wenn ich in Java codiere, würde ich (natürlich) Guava verwenden . (Und ganz sicher nicht Apache Commons.)

Setzen Sie diese Konstante irgendwo ein, z. B. in die Klasse "StringUtils":

public static final Ordering<String> CASE_INSENSITIVE_NULL_SAFE_ORDER =
    Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); // or nullsFirst()

Dann in public class Metadata implements Comparable<Metadata>:

@Override
public int compareTo(Metadata other) {
    int result = CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.value, other.value);
}    

Dies ist natürlich fast identisch mit der Apache Commons-Version (beide verwenden JDKs CASE_INSENSITIVE_ORDER ), wobei die Verwendung nullsLast()die einzige Guava-spezifische Sache ist. Diese Version ist einfach deshalb vorzuziehen, weil Guava als Abhängigkeit den Commons-Sammlungen vorzuziehen ist. (Wie alle zustimmen .)

Wenn Sie sich gefragt haben Ordering, beachten Sie, dass es implementiert Comparator. Dies ist besonders für komplexere Sortieranforderungen sehr praktisch, da Sie beispielsweise mehrere Bestellungen mit verketten können compound(). Lesen Sie die Bestellung erklärt für mehr!

Jonik
quelle
2
String.CASE_INSENSITIVE_ORDER macht die Lösung wirklich viel sauberer. Schönes Update.
Patrick
2
Wenn Sie Apache Commons trotzdem verwenden, gibt es eine, ComparatorChainsodass Sie keine eigene compareToMethode benötigen .
Amöbe
13

Ich empfehle immer, Apache Commons zu verwenden, da es höchstwahrscheinlich besser ist als eines, das Sie selbst schreiben können. Außerdem können Sie dann "echte" Arbeit leisten, anstatt sie neu zu erfinden.

Die Klasse, an der Sie interessiert sind, ist der Nullkomparator . Sie können damit Nullen hoch oder niedrig setzen. Sie geben ihm auch einen eigenen Komparator, den Sie verwenden können, wenn die beiden Werte nicht null sind.

In Ihrem Fall können Sie eine statische Elementvariable haben, die den Vergleich durchführt, und dann compareToverweist Ihre Methode nur darauf.

So etwas wie

class Metadata implements Comparable<Metadata> {
private String name;
private String value;

static NullComparator nullAndCaseInsensitveComparator = new NullComparator(
        new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                // inputs can't be null
                return o1.compareToIgnoreCase(o2);
            }

        });

@Override
public int compareTo(Metadata other) {
    if (other == null) {
        return 1;
    }
    int res = nullAndCaseInsensitveComparator.compare(name, other.name);
    if (res != 0)
        return res;

    return nullAndCaseInsensitveComparator.compare(value, other.value);
}

}}

Auch wenn Sie sich dazu entschließen, Ihre eigene zu würfeln, sollten Sie diese Klasse berücksichtigen, da sie sehr nützlich ist, wenn Sie Listen bestellen, die Nullelemente enthalten.

Patrick
quelle
Danke, ich hatte irgendwie gehofft, dass es so etwas in Commons geben würde! In diesem Fall habe ich es jedoch nicht verwendet: stackoverflow.com/questions/481813/…
Jonik
Gerade erkannt, dass Ihr Ansatz mithilfe von String.CASE_INSENSITIVE_ORDER vereinfacht werden kann. Siehe meine bearbeitete Antwort.
Jonik
Dies ist gut, aber die Prüfung "if (other == null) {" sollte nicht vorhanden sein. Das Javadoc für Comparable besagt, dass compareTo eine NullPointerException auslösen sollte, wenn other null ist.
Daniel Alexiuc
7

Ich weiß, dass Ihre Frage möglicherweise nicht direkt beantwortet wird, da Sie gesagt haben, dass Nullwerte unterstützt werden müssen.

Ich möchte jedoch nur darauf hinweisen, dass die Unterstützung von Nullen in compareTo nicht mit dem in den offiziellen Javadocs für Comparable beschriebenen compareTo-Vertrag übereinstimmt :

Beachten Sie, dass null keine Instanz einer Klasse ist und e.compareTo (null) eine NullPointerException auslösen sollte, obwohl e.equals (null) false zurückgibt.

Also würde ich entweder NullPointerException explizit auslösen oder es einfach beim ersten Mal auslösen lassen, wenn das Null-Argument dereferenziert wird.

Piotr Sobczyk
quelle
4

Sie können Methode extrahieren:

public int cmp(String txt, String otherTxt)
{
    if ( txt == null )
        return otjerTxt == null ? 0 : 1;

    if ( otherTxt == null )
          return 1;

    return txt.compareToIgnoreCase(otherTxt);
}

public int compareTo(Metadata other) {
   int result = cmp( name, other.name); 
   if ( result != 0 )  return result;
   return cmp( value, other.value); 

}}

Yoni Roit
quelle
2
Sollte "0: 1" nicht "0: -1" sein?
Rolf Kristensen
3

Sie können Ihre Klasse so gestalten, dass sie unveränderlich ist (Effective Java 2nd Ed. Enthält einen großartigen Abschnitt dazu, Punkt 15: Minimieren der Veränderlichkeit) und bei der Erstellung sicherstellen, dass keine Nullen möglich sind (und bei Bedarf das Nullobjektmuster verwenden ). Dann können Sie alle diese Überprüfungen überspringen und sicher annehmen, dass die Werte nicht null sind.

Fabian Steeg
quelle
Ja, das ist im Allgemeinen eine gute Lösung und vereinfacht viele Dinge - aber hier war ich mehr an dem Fall interessiert, in dem Nullwerte aus dem einen oder anderen Grund zulässig sind und berücksichtigt werden müssen :)
Jonik
2

Ich suchte nach etwas Ähnlichem und das schien ein bisschen kompliziert zu sein, also tat ich das. Ich denke, es ist etwas einfacher zu verstehen. Sie können es als Komparator oder als Einzeiler verwenden. Für diese Frage würden Sie zu compareToIgnoreCase () wechseln. Wie es ist, schweben Nullen auf. Sie können die 1, -1 umdrehen, wenn Sie möchten, dass sie sinken.

StringUtil.NULL_SAFE_COMPARATOR.compare(getName(), o.getName());

.

public class StringUtil {
    public static final Comparator<String> NULL_SAFE_COMPARATOR = new Comparator<String>() {

        @Override
        public int compare(final String s1, final String s2) {
            if (s1 == s2) {
                //Nulls or exact equality
                return 0;
            } else if (s1 == null) {
                //s1 null and s2 not null, so s1 less
                return -1;
            } else if (s2 == null) {
                //s2 null and s1 not null, so s1 greater
                return 1;
            } else {
                return s1.compareTo(s2);
            }
        }
    }; 

    public static void main(String args[]) {
        final ArrayList<String> list = new ArrayList<String>(Arrays.asList(new String[]{"qad", "bad", "sad", null, "had"}));
        Collections.sort(list, NULL_SAFE_COMPARATOR);

        System.out.println(list);
    }
}
Dustin
quelle
2

Wir können Java 8 verwenden, um einen nullfreundlichen Vergleich zwischen Objekten durchzuführen. Angenommen, ich habe eine Boy-Klasse mit 2 Feldern: String-Name und Integer-Alter und ich möchte zuerst Namen und dann Alter vergleichen, wenn beide gleich sind.

static void test2() {
    List<Boy> list = new ArrayList<>();
    list.add(new Boy("Peter", null));
    list.add(new Boy("Tom", 24));
    list.add(new Boy("Peter", 20));
    list.add(new Boy("Peter", 23));
    list.add(new Boy("Peter", 18));
    list.add(new Boy(null, 19));
    list.add(new Boy(null, 12));
    list.add(new Boy(null, 24));
    list.add(new Boy("Peter", null));
    list.add(new Boy(null, 21));
    list.add(new Boy("John", 30));

    List<Boy> list2 = list.stream()
            .sorted(comparing(Boy::getName, 
                        nullsLast(naturalOrder()))
                   .thenComparing(Boy::getAge, 
                        nullsLast(naturalOrder())))
            .collect(toList());
    list2.stream().forEach(System.out::println);

}

private static class Boy {
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Boy(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "name: " + name + " age: " + age;
    }
}

und das Ergebnis:

    name: John age: 30
    name: Peter age: 18
    name: Peter age: 20
    name: Peter age: 23
    name: Peter age: null
    name: Peter age: null
    name: Tom age: 24
    name: null age: 12
    name: null age: 19
    name: null age: 21
    name: null age: 24
Leo Ng
quelle
1

Für den speziellen Fall, in dem Sie wissen, dass die Daten keine Nullen haben (immer eine gute Idee für Zeichenfolgen) und die Daten sehr groß sind, führen Sie noch drei Vergleiche durch, bevor Sie die Werte tatsächlich vergleichen. Wenn Sie sicher sind, dass dies Ihr Fall ist , Sie können ein bisschen optimieren. YMMV als lesbarer Code übertrifft geringfügige Optimierungen:

        if(o1.name != null && o2.name != null){
            return o1.name.compareToIgnoreCase(o2.name);
        }
        // at least one is null
        return (o1.name == o2.name) ? 0 : (o1.name != null ? 1 : -1);
kisna
quelle
1
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Comparator;

public class TestClass {

    public static void main(String[] args) {

        Student s1 = new Student("1","Nikhil");
        Student s2 = new Student("1","*");
        Student s3 = new Student("1",null);
        Student s11 = new Student("2","Nikhil");
        Student s12 = new Student("2","*");
        Student s13 = new Student("2",null);
        List<Student> list = new ArrayList<Student>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s11);
        list.add(s12);
        list.add(s13);

        list.sort(Comparator.comparing(Student::getName,Comparator.nullsLast(Comparator.naturalOrder())));

        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            Student student = (Student) iterator.next();
            System.out.println(student);
        }


    }

}

Ausgabe ist

Student [name=*, id=1]
Student [name=*, id=2]
Student [name=Nikhil, id=1]
Student [name=Nikhil, id=2]
Student [name=null, id=1]
Student [name=null, id=2]
Nikhil Kumar K.
quelle
1

Eine der einfachen Möglichkeiten zur Verwendung von NullSafe Comparator ist die Verwendung der Spring-Implementierung. Im Folgenden finden Sie eines der einfachen Beispiele, auf die verwiesen wird:

public int compare(Object o1, Object o2) {
        ValidationMessage m1 = (ValidationMessage) o1;
        ValidationMessage m2 = (ValidationMessage) o2;
        int c;
        if (m1.getTimestamp() == m2.getTimestamp()) {
            c = NullSafeComparator.NULLS_HIGH.compare(m1.getProperty(), m2.getProperty());
            if (c == 0) {
                c = m1.getSeverity().compareTo(m2.getSeverity());
                if (c == 0) {
                    c = m1.getMessage().compareTo(m2.getMessage());
                }
            }
        }
        else {
            c = (m1.getTimestamp() > m2.getTimestamp()) ? -1 : 1;
        }
        return c;
    }
Amandeep Singh
quelle
0

Ein weiteres Beispiel für Apache ObjectUtils. Kann andere Arten von Objekten sortieren.

@Override
public int compare(Object o1, Object o2) {
    String s1 = ObjectUtils.toString(o1);
    String s2 = ObjectUtils.toString(o2);
    return s1.toLowerCase().compareTo(s2.toLowerCase());
}
snp0k
quelle
0

Dies ist meine Implementierung, mit der ich meine ArrayList sortiere. Die Nullklassen werden bis zum letzten sortiert.

In meinem Fall erweitert EntityPhone EntityAbstract und mein Container ist List <EntityAbstract>.

Die Methode "compareIfNull ()" wird für die nullsichere Sortierung verwendet. Die anderen Methoden dienen der Vollständigkeit und zeigen, wie compareIfNull verwendet werden kann.

@Nullable
private static Integer compareIfNull(EntityPhone ep1, EntityPhone ep2) {

    if (ep1 == null || ep2 == null) {
        if (ep1 == ep2) {
            return 0;
        }
        return ep1 == null ? -1 : 1;
    }
    return null;
}

private static final Comparator<EntityAbstract> AbsComparatorByName = = new Comparator<EntityAbstract>() {
    @Override
    public int compare(EntityAbstract ea1, EntityAbstract ea2) {

    //sort type Phone first.
    EntityPhone ep1 = getEntityPhone(ea1);
    EntityPhone ep2 = getEntityPhone(ea2);

    //null compare
    Integer x = compareIfNull(ep1, ep2);
    if (x != null) return x;

    String name1 = ep1.getName().toUpperCase();
    String name2 = ep2.getName().toUpperCase();

    return name1.compareTo(name2);
}
}


private static EntityPhone getEntityPhone(EntityAbstract ea) { 
    return (ea != null && ea.getClass() == EntityPhone.class) ?
            (EntityPhone) ea : null;
}
Engel Koh
quelle
0

Wenn Sie einen einfachen Hack wollen:

arrlist.sort((o1, o2) -> {
    if (o1.getName() == null) o1.setName("");
    if (o2.getName() == null) o2.setName("");

    return o1.getName().compareTo(o2.getName());
})

Wenn Sie Nullen an das Ende der Liste setzen möchten, ändern Sie dies einfach in der obigen Metod

return o2.getName().compareTo(o1.getName());
MarsPeople
quelle