5

Trước Java 8, chúng tôi thực hiện Comparable.compareTo(...) như thế này:Thay CompareToBuilder với Java 8 của Comperator.comparing (...) thenComparing (...)

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

Tính đến Java 8, chúng ta có thể làm điều đó như này:

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

Cách Java 8 mới có thể cho phép chúng tôi xóa phụ thuộc commons-lang3. Có phải đó là cách Java 8 mới nhanh hơn không? Có cách nào để tự động di chuyển không? Tôi không tìm thấy ý định IntelliJ cho nó.


Chú ý rằng nó trở nên phức tạp hơn một chút khi có lệnh ngược lại và so sánh không tự nhiên có liên quan đến:

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

trở thành

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

Trả lời

2

Tôi không nghĩ có bất kỳ kiểm tra được xác định trước cho điều đó. Bạn có thể cố gắng sử dụng structural-search của IntelliJ, mặc dù tôi nghĩ rằng nó có thể là khá phức tạp để làm điều đó cho mọi trường hợp có thể. Một khả năng cho một trường hợp đơn giản với hai sự so sánh có thể là như sau:

tìm kiếm mẫu (số xuất hiện của $TYPE$$z$ là 2):

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

thay thế mẫu:

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

Tôi không phải là một chuyên gia về tìm kiếm cấu trúc, nhưng tôi đoán bạn sẽ phải thực hiện một mô hình khác cho các cuộc gọi có nhiều so sánh hơn.

6

Nếu bạn viết nó theo cách này

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

bạn đang lãng phí hiệu suất bằng cách xây dựng một mới Comparator cho mỗi so sánh. Và nó rõ ràng là vô nghĩa khi nhìn vào mã xung quanh. Phương thức compare(Person a, Person b) chắc chắn là một phần của lớp thực hiện Comparator<Person>, mà bạn khởi tạo ở một số nơi để có được trình so sánh mong muốn. Thay vào đó, bạn nên thay thế ví dụ bằng một số duy nhất Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName) được sử dụng trong toàn bộ hoạt động.

Ví dụ:

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

hoặc quảng cáo hoc

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

Nếu bạn sử dụng nó như vậy, nó rất có thể sẽ nhanh hơn. Tuy nhiên, bạn sẽ thấy, rằng không có sự thay thế dựa trên mẫu đơn giản nào có thể. Bạn phải thay thế các trang web sử dụng của lớp với cấu trúc khai báo đơn giản đó và đưa ra quyết định có sử dụng một cá thể so sánh được chia sẻ cho nhiều trang web sử dụng hoặc tạo nó không. Sau đó, bạn có thể xóa toàn bộ lớp triển khai cũ hoặc ít nhất, loại bỏ chức năng so sánh khỏi nó nếu nó vẫn phục vụ các mục đích khác.

+0

Tôi cần triển khai so sánh tự nhiên của Người, vì vậy tôi không thể áp dụng các thay đổi được đề xuất này. Bạn có tin rằng Comparator.comparing (...) cũng chậm hơn CompareToBuilder không? –

+1

Nếu bạn thực hiện thứ tự tự nhiên, phương thức phải là 'compareTo (Person)' chứ không phải là 'so sánh (Person, Person)', vì vậy câu hỏi là gây hiểu nhầm. Tôi không nghĩ rằng việc sử dụng 'Comparator.comparing' sẽ chậm hơn' CompareToBuilder', nhưng bạn vẫn có thể cải thiện nó bằng cách khai báo trường 'static final' như được hiển thị trong câu trả lời của tôi và thực hiện' compareTo (Person) 'là' trả về BY_NAME.compare (điều này, khác); – Holger

+0

Điểm tốt. Trên thực tế tôi có trường hợp sử dụng mà nó tự nhiên và tôi đã sử dụng trường hợp mà nó là một Comperator tái sử dụng (như trên). Tôi hiểu tại sao nó không còn cần thiết để biến Comperator thành một lớp riêng biệt. –

Các vấn đề liên quan