Java 8 Comparator nullsFirst naturalOrder困惑

这可能是一个简单的问题,但我想清楚地理解它……

我有这样的代码:

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+'}';} } 

我正在测试这段代码:

 import static java.util.Comparator.*; private void nullsFirstTesting() { final Comparatorcomparator = comparing(Persona::getName,nullsFirst(naturalOrder())); final Listpersons = 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); } 

这显示以下结果:

 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} 

这些结果对我来说还可以,但我有一个问题需要理解。

当我忽略new Persona(5,null)对象并通过比较器时:

 final Comparatorcomparator = comparing(Persona::getName); 

它就像一个魅力。 我的排序是按natural order of name property 。 当我添加name=null的对象时出现问题,我只是觉得我需要这样的比较器。

 final Comparatorcomparator = comparing(Persona::getName,nullsFirst()); 

我的想法是错误的 :“好的,当名称非空时,它们按natural order of name排序,就像前一个比较器一样,如果它们为null它们将是第一个, 但我的非空名称仍然会被排序自然秩序 “。

但正确的代码是这样的:

 final Comparatorcomparator = comparing(Persona::getName,nullsFirst(naturalOrder())); 

我不理解nullsFirst的参数。 我只是认为natural order of namenatural order of name将显式[默认]甚至处理null值。

但文档说:

返回一个空值友好的比较器,它将null视为小于非null。 当两者都为null ,它们被认为是相等的。 如果两者都为非null,则使用指定的Comparator来确定顺序。 如果指定的比较器为null ,则返回的比较器将所有非空值视为相等。

这一行:“如果两者都是非null,则使用指定的Comparator来确定顺序。”

我很困惑何时以及如何明确地设定自然顺序或何时推断自然顺序。

“自然顺序”比较器(使用仅与一个参数comparing时得到的) 不会处理空值。 (我不知道你在哪里得到它的想法。) Comparable类的“自然顺序”由compareTo()方法定义,它使用如下:

 obj1.compareTo(obj2) 

显然,如果obj1为null,这将不起作用; 对于String ,它也会抛出obj2的exception为null。

naturalOrder()方法返回比较两个对象的Comparator 。 javadoc显式地说这个比较器在比较null时抛出NullPointerException

nullsFirst()方法(和nullsLast()类似)基本上将Comparator转换为新的Comparator 。 你输入一个比较器,如果它试图比较null,它可能抛出一个exception,它会吐出一个新的比较器,它的工作方式相同,只是它允许空参数。 所以这就是为什么你需要一个nullsFirst参数的原因 – 因为它在现有的比较器之上建立一个新的比较器,你告诉它现有的比较器是什么。

那么,如果省略参数,为什么不给你自然顺序呢? 因为他们没有这样定义。 nullsFirst是在javadoc中定义的,用于获取参数:

 static  Comparator nullsFirst(Comparator comparator) 

我认为,如果设计师想要,他们可以添加一个不带参数的重载:

 static  Comparator nullsFirst() // note: not legal 

这与使用nullsFirst(naturalOrder()) 。 但他们没有,所以你不能那样使用它。

尝试:

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

我有一个员工列表,其中包含姓名和身​​份的学生。

  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 list = new ArrayList(); 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); } } } 

产生输出为

 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]