5

Vor Java 8 implementierten wir Comparable.compareTo(...) wie folgt aus:ersetzen CompareToBuilder mit Java 8 des Comperator.comparing (...) thenComparing (...)

public int compare(Person a, Person b) { 
    return new CompareToBuilder() 
      .append(a.getLastName(), b.getLastName()) 
      .append(a.getFirstName(), b.getFirstName()) 
      .toComparison(); 
} 

Ab Java 8, wir können es tun, wie dies:

public int compare(Person a, Person b) { 
    return Comparator 
      .comparing(Person::getLastName) 
      .thenComparing(Person::getFirstName) 
      .compare(a, b); 
} 

die neue Java 8 Art und Weise könnte es uns ermöglichen, die commons-lang3 Abhängigkeit fallen zu lassen. Ist das neue Java 8 schneller? Gibt es eine Möglichkeit, automatisch zu migrieren? Ich habe keine IntelliJ Absicht dafür gefunden.


Beachten Sie, dass es ein bisschen komplexer wird, wenn es umgekehrt Aufträge und nicht natürliche Vergleich beteiligt ist:

public int compare(SingleBenchmarkResult a, SingleBenchmarkResult b) { 
    return new CompareToBuilder() 
      .append(b.hasAnyFailure(), a.hasAnyFailure()) // Reverse 
      .append(a.getAverageScore(), b.getAverageScore(), resilientScoreComparator) 
      .toComparison(); 
} 

public int compare(SingleBenchmarkResult a, SingleBenchmarkResult b) { 
    return Comparator 
      .comparing(SingleBenchmarkResult::hasAnyFailure, Comparator.reverseOrder()) // Reverse 
      .thenComparing(SingleBenchmarkResult::getAverageScore, resilientScoreComparator) 
      .compare(a, b); 
} 

Antwort

2

wird glaube ich nicht, dass es irgendwelche gibt vordefinierte Inspektion dafür. Sie könnten versuchen, IntelliJ's structural-search zu verwenden, obwohl ich denke, dass es für jeden möglichen Fall ziemlich schwierig ist, das zu tun. Eine Möglichkeit für einen einfachen Fall mit zwei Vergleiche könnten folgende sein:

Suchvorlage (Vorkommen Anzahl der $TYPE$ und $z$ ist 2):

$ReturnType$ $MethodName$($TYPE$ $z$) { 
     return new CompareToBuilder() 
       .append($A$.$m$(), $B$.$m$()) 
       .append($A$.$m1$(), $B$.$m1$()) 
       .toComparison(); 
    } 

Ersatzvorlage:

$ReturnType$ $MethodName$($TYPE$ $z$) { 
    return java.util.Comparator 
      .comparing($TYPE$::$m$) 
      .thenComparing($TYPE$::$m1$) 
      .compare($A$, $B$); 
} 

Ich bin kein Experte für strukturelle Suche, aber ich denke, Sie müssten ein weiteres Muster für Anrufe mit mehr oder weniger Vergleichen erstellen.

6

Wenn Sie es auf diese Weise

public int compare(Person a, Person b) { 
    return Comparator 
      .comparing(Person::getLastName) 
      .thenComparing(Person::getFirstName) 
      .compare(a, b); 
} 

Sie verschwenden Schreibleistung durch einen neuen Comparator für jeden Vergleich zu konstruieren. Und es sollte offensichtlich unsinnig sein, wenn man den umgebenden Code betrachtet. Die compare(Person a, Person b) Methode ist sicherlich Teil einer Klasse, die Comparator<Person> implementiert, die Sie an einer Stelle instanziieren, um den gewünschten Komparator zu erhalten. Sie sollten die Instanz anstelle der Instanz durch eine einzige Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName) Instanz ersetzen, die während des gesamten Vorgangs verwendet wird.

z.

// reusable 
static final Comparator<Person> By_NAME = Comparator 
      .comparing(Person::getLastName).thenComparing(Person::getFirstName); 

oder Ad-hoc-

listOfPersons.sort(Comparator.comparing(Person::getLastName) 
          .thenComparing(Person::getFirstName)); 

Wenn Sie es auf diese Weise zu verwenden, ist es sehr wahrscheinlich, schneller zu sein. Sie sollten jedoch sehen, dass kein einfacher musterbasierter Austausch möglich ist. Sie müssen die Verwendungsstellen der Klasse durch dieses einfache deklarative Konstrukt ersetzen und eine Entscheidung treffen, ob Sie eine gemeinsam genutzte Vergleicherinstanz für mehrere Verwendungsstellen verwenden oder sie ad-hoc erstellen möchten. Dann können Sie die gesamte alte Implementierungsklasse entfernen oder zumindest die Komparatorfunktionalität entfernen, wenn sie noch anderen Zwecken dient.

+0

Ich muss den natürlichen Vergleich der Person implementieren, damit ich diese vorgeschlagenen Änderungen nicht anwenden kann. Glauben Sie, dass Comparator.comparing (...) auch langsamer ist als CompareToBuilder? –

+1

Wenn Sie die natürliche Reihenfolge implementieren, sollte die Methode "compareTo (Person)" statt "compare (Person, Person)" sein, also war die Frage irreführend. Ich glaube nicht, dass die Verwendung von 'Comparator.comparing' langsamer ist als' CompareToBuilder', aber Sie können es dennoch verbessern, indem Sie das 'static final' Feld wie in meiner Antwort gezeigt deklarieren und' compareTo (Person) 'als' implementieren return BY_NAME.compare (this, other); '. – Holger

+0

Guter Punkt. Tatsächlich habe ich Anwendungsfälle, wo es eine natürliche Reihenfolge ist und ich habe Anwendungsfälle, wo es ein wiederverwendbarer Comperator ist (wie oben). Ich sehe, warum es nicht mehr nötig ist, diesen spezialisierten Comperator zu einer separaten Klasse zu machen. –