Null-Safe-Mapping-Komparator mit Standardimplementierungen

76

Gibt es eine integrierte Möglichkeit, einen nullsicheren Mapping-Komparator in Java 8 zu erstellen, ohne eine eigene Implementierung von zu schreiben Comparator?

Wenn der folgende Code ausgeführt wird, wird eine NPE verursacht, da das keyExtractorArgument von Comparator.comparing()möglicherweise einen nullWert zurückgibt:

public class ToSort
{

    private String sortBy;

    public ToSort(String sortBy)
    {
        this.sortBy = sortBy;
    }

    public String getSortBy()
    {
        return sortBy;
    }

    public static void main(String[] args)
    {
        // mapping comparator
        Comparator<ToSort> comp = Comparator.comparing(ToSort::getSortBy);                          
        SortedSet<ToSort> set = new TreeSet<>(comp);
        ToSort o1 = new ToSort("1");
        ToSort o2 = new ToSort(null);

        set.add(o1);

        System.out.println(set.contains(o2)); //NPE because o2.getSortBy() == null

    }
}

Ausnahme im Thread "main" java.lang.NullPointerException bei java.util.Comparator.lambda $ im Vergleich von $ 77a9974f $ 1 (Comparator.java:469) bei java.util.Comparator $$ Lambda $ 2 / 1480010240.compare (Unbekannte Quelle) bei java.util.Comparators $ NullComparator.compare (Comparators.java:83) bei java.util.TreeMap.getEntryUsingComparator (TreeMap.java:376) bei java.util.TreeMap.getEntry (TreeMap.java:345) bei java.util .TreeMap.containsKey (TreeMap.java:232) unter java.util.TreeSet.contains (TreeSet.java:234) unter test.ToSort.main (ToSort.java:48)

Verwenden von

Comparator<ToSort> comp = Comparator.nullsFirst(Comparator.comparing(ToSort::getSortBy));

funktioniert auch nicht, da nur ToSortObjekte nullrichtig betreten werden.

Ich weiß, wie man meine eigene ComparatorImplementierung schreibt, ich suche nur nach einer "eleganteren" Lösung wie

Comparator.comparingNullsFirst(ToSort::getSortBy)
flo
quelle

Antworten:

132

Eine mögliche Lösung gefunden:

Comparator.comparing(ToSort::getSortBy, 
      Comparator.nullsFirst(Comparator.naturalOrder())
)
flo
quelle
Der Grund, warum diese Lösung funktioniert, liegt in der Reihenfolge der Verschachtelung der Komparatoren. In Ihrer Frage war der innerste Komparator (und damit der erste, der ausgeführt wurde) ToSort::getSortByund der nullsFirstwurde darum gewickelt. In dieser Antwort das nullsFirstist Komparator nun zuerst ausgeführt und bietet Sicherheit vor den Null-Rückkehr getSortByAnrufe
Geert