2014-10-14 21 views
5

này có thể là một câu hỏi đơn giản nhưng tôi muốn hiểu nó rõ ràng ...Java 8 sánh nullsFirst naturalOrder nhầm lẫn

Tôi có một mã như thế này:

public final class Persona 
{ 
    private final int id; 
    private final String name 
    public Persona(final int id,final String name) 
    { 
     this.id = id; 
     this.name = name; 
    } 
    public int getId(){return id;}  
    public String getName(){return name;}  
    @Override 
    public String toString(){return "Persona{" + "id=" + id + ", name=" + name+'}';}  
} 

Và tôi đang thử nghiệm mã này :

import static java.util.Comparator.*; 
private void nullsFirstTesting() 
{    
    final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst(naturalOrder())); 
    final List<Persona>persons = Arrays.asList(new Persona(1,"Cristian"),new Persona(2,"Guadalupe"),new Persona(3,"Cristina"),new Persona(4,"Chinga"),new Persona(5,null)); 
    persons 
      .stream() 
      .sorted(comparator) 
      .forEach(System.out::println);       
} 

Điều này cho thấy kết quả như sau:

Persona{id=5, name=null} 
Persona{id=4, name=Chinga} 
Persona{id=1, name=Cristian} 
Persona{id=3, name=Cristina} 
Persona{id=2, name=Guadalupe} 

Những kết quả này phù hợp với tôi nhưng tôi đã hiểu được vấn đề.

Khi tôi bỏ qua các đối tượng new Persona(5,null) và tôi vượt qua so sánh:

final Comparator<Persona>comparator = comparing(Persona::getName); 

Nó hoạt động như một nét duyên dáng. Phân loại của tôi là theo số natural order of name property. Vấn đề phát sinh khi tôi thêm đối tượng với name=null, tôi chỉ nghĩ rằng tôi sẽ cần so sánh của tôi như thế này.

final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst()); 

suy nghĩ của tôi là sai lầm : "OK, khi tên là phi null, họ đều được sắp xếp trong natural order of name, giống như so sánh trước, và nếu họ có null họ sẽ là người đầu tiên nhưng không của tôi tên rỗng sẽ vẫn được sắp xếp theo thứ tự tự nhiên ".

Nhưng mã đúng là thế này:

final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst(naturalOrder())); 

Tôi không hiểu các tham số để nullsFirst. Tôi chỉ nghĩ rằng natural order of name sẽ rõ ràng [mặc định] thậm chí xử lý các giá trị null.

Nhưng các tài liệu nói:

Trả về một so sánh null-thân thiện mà coi null là ít so với người không null. Khi cả hai đều là null, chúng được coi là bằng nhau. Nếu cả hai đều không có giá trị rỗng, số Comparator được chỉ định được sử dụng để xác định thứ tự. Nếu so sánh được chỉ định là null, thì trình so sánh được trả về xem xét tất cả các giá trị không null phải bằng nhau.

Dòng này: "Nếu cả hai đều không rỗng, chỉ định Comparator được chỉ định để xác định thứ tự".

Tôi bối rối khi nào và như thế nào thứ tự tự nhiên nên được đặt rõ ràng hoặc khi chúng được suy ra.

+3

Lưu ý * "Nếu so sánh quy định là 'null', sau đó bộ so sánh trả về xem xét tất cả các giá trị không null bằng nhau." * Nói cách khác, bạn có thể làm 'nullsFirst (null)'; tuy nhiên nó chỉ đơn thuần là sắp xếp các giá trị rỗng vào mặt trước mà không phân loại các giá trị không rỗng. Tài liệu thực sự giải thích nó khá tốt. – Radiodef

+0

@chiperotiz vì vậy bạn đã giải quyết nó như thế nào? Bạn có thể sắp xếp theo null trước và sau đó là Thứ tự tự nhiên? – Unheilig

+1

có sử dụng mã này 'cuối cùng so sánh so sánh = so sánh (Persona :: getName, nullsFirst (naturalOrder())); ' – chiperortiz

Trả lời

17

Trình so sánh "thứ tự tự nhiên", đó là những gì bạn nhận được khi bạn sử dụng comparing chỉ với một tham số, không không xử lý giá trị rỗng. (Tôi không chắc bạn đã có ý tưởng về nó ở đâu.) Các "trật tự tự nhiên" của một lớp Comparable được xác định theo phương pháp compareTo(), được sử dụng như thế này:

obj1.compareTo(obj2) 

Rõ ràng điều này sẽ không hoạt động nếu obj1 là null; cho String, nó cũng sẽ ném một ngoại lệ là obj2 là không.

Phương thức naturalOrder() trả về một số Comparator so sánh hai đối tượng. Các javadoc rõ ràng nói rằng so sánh này ném NullPointerException khi so sánh null.

Phương pháp nullsFirst() (và nullsLast() tương tự) về cơ bản biến đổi Comparator thành Comparator mới. Bạn đặt trong một so sánh có thể ném một ngoại lệ nếu nó cố gắng để so sánh null, và nó spits ra một so sánh mới hoạt động theo cùng một cách ngoại trừ việc nó cho phép đối số null. Vì vậy, đó là lý do tại sao bạn cần một tham số để nullsFirst - bởi vì nó xây dựng một trình so sánh mới trên đầu trang của một trình so sánh hiện có và bạn cho nó biết bộ so sánh hiện tại là gì.

Vậy tại sao nó không cung cấp cho bạn thứ tự tự nhiên nếu bạn bỏ tham số? Bởi vì họ không định nghĩa nó theo cách đó. nullsFirst được định nghĩa trong javadoc để có một tham số:

static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) 

Tôi nghĩ rằng nếu các nhà thiết kế muốn, họ có thể thêm vào một tình trạng quá tải mà mất không tham số:

static <T> Comparator<T> nullsFirst() // note: not legal 

rằng sẽ là như nhau khi sử dụng nullsFirst(naturalOrder()). Nhưng họ không làm vậy, nên bạn không thể sử dụng nó như thế.

+0

Xin chào ajb tôi không bao giờ nghĩ rằng chỉ có tham số so sánh sẽ được xử lý nulls .. tôi chỉ nghĩ rằng nullsFirst () phương pháp sẽ đặt nulls đầu tiên và không nulls sẽ được sắp xếp theo thứ tự tự nhiên ... nhưng như bạn đã nói 'static Comparator nullsFirst() // note: not legal' simple is not legal. tôi chỉ nghĩ rằng sẽ tốt đẹp như bạn nói một nullFirst mà không có tham số nên được naturalOrder() như mặc định .. cảm ơn. – chiperortiz

11

Hãy thử:

final Comparator<Persona> comparator = 
    comparing(Persona::getName, nullsFirst(naturalOrder())); 
1

Tôi có một danh sách các nhân viên với sinh viên với tên và id ..

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); 
     } 


    } 

} 

Tạo đầu ra như

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]