Java 8 Comparator nullsFirst naturalOrder困惑

chi*_*tiz 14 java sorting string comparator java-8

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

我有这样的代码:

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+'}';}    
 }
Run Code Online (Sandbox Code Playgroud)

我正在测试这段代码:

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);                           
}
Run Code Online (Sandbox Code Playgroud)

这显示以下结果:

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}
Run Code Online (Sandbox Code Playgroud)

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

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

final Comparator<Persona>comparator = comparing(Persona::getName);
Run Code Online (Sandbox Code Playgroud)

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

final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst());
Run Code Online (Sandbox Code Playgroud)

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

但正确的代码是这样的:

final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst(naturalOrder()));
Run Code Online (Sandbox Code Playgroud)

我不明白参数nullsFirst.我只是认为natural order of name明确[默认]会处理null值.

但文档说:

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

这一行:"如果两者都是非null,则指定Comparator用于确定顺序."

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

ajb*_*ajb 27

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

obj1.compareTo(obj2)
Run Code Online (Sandbox Code Playgroud)

显然,如果obj1为null,这将不起作用; for String,如果obj2为null ,它也会抛出异常.

naturalOrder()方法返回一个Comparator比较两个对象的方法.在javadoc中明确地说,这种比较引发NullPointerException比较空的时候.

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

那么,如果省略参数,它为什么不给你自然顺序呢?因为他们没有这样定义. nullsFirstjavadoc中定义了一个参数:

static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
Run Code Online (Sandbox Code Playgroud)

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

static <T> Comparator<T> nullsFirst()  // note: not legal
Run Code Online (Sandbox Code Playgroud)

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


小智 22

尝试:

final Comparator<Persona> comparator =
  comparing(Persona::getName, nullsFirst(naturalOrder()));
Run Code Online (Sandbox Code Playgroud)


小智 5

我有一份带有学生姓名和 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);
        }


    }

}
Run Code Online (Sandbox Code Playgroud)

产生输出为

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]
Run Code Online (Sandbox Code Playgroud)