5

Przed Java 8 wdrożyliśmy Comparable.compareTo(...) takiego:Wymień CompareToBuilder z Java 8 za Comperator.comparing (...) thenComparing (...)

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

Jako Java 8, możemy to zrobić jak to:

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

nowy Java 8 sposób może pozwolić nam spadać zależność commons-lang3. Czy ta nowa Java 8 jest szybsza? Czy istnieje sposób automatycznej migracji? Nie znalazłem intencji IntelliJ dla tego.


Zauważ, że staje się nieco bardziej skomplikowane, gdy istnieją odwrotnej zamówienia i nie naturalne porównanie jest zaangażowany:

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

staje

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

Odpowiedz

2

Nie sądzę, istnieje jakikolwiek wcześniej zdefiniowana inspekcja. Możesz spróbować użyć IntelliJ's structural-search, choć myślę, że może to być dość trudne, aby zrobić to dla każdego możliwego przypadku. Jedną z możliwości prostym przypadku z dwóch porównań mogą być następujące:

wyszukiwania szablon (liczba Występowanie $TYPE$ i $z$ jest 2): template

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

wymiana:

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

jestem nie jest ekspertem od wyszukiwania strukturalnego, ale wydaje mi się, że musiałbyś stworzyć inny wzór dla połączeń z mniej lub więcej porównaniami.

6

Jeśli piszesz to tak

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

tracisz wydajność dzięki budowie nowej Comparator dla każdego porównania. I powinno to być oczywiście bezsensowne, patrząc na otaczający kod. Metoda compare(Person a, Person b) z pewnością jest częścią klasy implementującej Comparator<Person>, którą tworzysz w pewnym miejscu, aby uzyskać pożądany komparator. Zamiast tego należy zamienić instancję na instancję przez jedyną instancję Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName) używaną w całej operacji.

E.g.

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

lub ad hoc

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

Jeśli używamy go w ten sposób, to jest bardzo prawdopodobne, aby być szybciej. Powinieneś jednak zauważyć, że nie ma prostego zastępowania opartego na wzorach. Musisz zastąpić strony używane w klasie tą prostą konstrukcją deklaratywną i zdecyduj, czy chcesz użyć współużytkowanej instancji porównawczej dla witryn z wieloma aplikacjami, czy utworzyć ją ad-hoc. Następnie możesz usunąć całą starą klasę implementacji lub przynajmniej usunąć z niej funkcję porównywania, jeśli nadal służy ona innym celom.

+0

Muszę wdrożyć naturalne porównanie osoby, więc nie mogę zastosować tych sugerowanych zmian. Czy uważasz, że Comparator.comparing (...) jest również wolniejszy niż CompareToBuilder? –

+1

Jeśli zaimplementujesz porządek naturalny, metodą powinno być 'compareTo (Person)' zamiast 'compare (Person, Person)', więc pytanie było mylące. Nie sądzę, że użycie 'Comparator.comparing' będzie wolniejsze niż' CompareToBuilder', ale mimo to możesz go poprawić deklarując pole 'static final' jak pokazano w mojej odpowiedzi i implementuję' compareTo (Person) 'as ' return BY_NAME.compare (ten, inny); '. – Holger

+0

Dobra uwaga. Właściwie mam przypadki użycia, w których jest to naturalny porządek i mam przypadki użycia, gdzie jest to wielokrotnego użytku Comperatora (jak wyżej). Rozumiem, dlaczego nie jest już konieczne, aby ten wyspecjalizowany Comperator był oddzielną klasą. –