这可能是一个简单的问题,但我想清楚地理解......
我有这样的代码:
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 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);
}
这显示以下结果:
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 Comparator<Persona>comparator = comparing(Persona::getName);
它就像一个魅力。我的排序是natural order of name property
。当我用name=null
添加对象时出现问题,我只是觉得我需要这样的比较器。
final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst());
我的想法是错误:“好的,当名称非空时,它们在natural order of name
中排序,就像上一个比较器一样,如果它们是null
它们将首先但我的非空名称仍将按自然顺序排序“。
但正确的代码是:
final Comparator<Persona>comparator = comparing(Persona::getName,nullsFirst(naturalOrder()));
我不理解nullsFirst
的参数。我只是认为natural order of name
会明确[默认]处理null
值。
但是文档说:
返回一个空值友好的比较器,它将
null
视为 小于非空。如果两者都是null
,则会考虑它们 等于。如果两者都为非null,则使用指定的Comparator
确定订单。如果指定的比较器为null
, 然后返回的比较器认为所有非空值都相等。
这一行:“如果两者都是非null,则使用指定的Comparator
来确定订单。”
我很困惑何时以及如何明确地设定自然顺序或推断它们。
答案 0 :(得分:25)
“自然顺序”比较器,即使用comparing
只有一个参数时得到的比例,不处理空值。 (我不知道你在哪里得到它的想法。)Comparable
类的“自然顺序”由compareTo()
方法定义,使用如下:
obj1.compareTo(obj2)
如果obj1
为空,显然这不起作用;对于String
,如果obj2
为空,它也会抛出异常。
naturalOrder()
方法返回一个比较两个对象的Comparator
。 javadoc明确表示比较器在比较null时会抛出NullPointerException
。
nullsFirst()
方法(和nullsLast()
类似)基本上将Comparator
转换为新的Comparator
。你输入一个比较器,如果它试图比较null,它可能抛出一个异常,它会吐出一个新的比较器,它的工作方式相同,只是它允许空参数。所以这就是你需要nullsFirst
参数的原因 - 因为它在现有的比较器之上建立了一个新的比较器,你告诉它现有的比较器是什么。
那么,如果省略参数,为什么不给你自然顺序呢?因为他们没有这样定义。 javadoc中定义了nullsFirst
来获取参数:
static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
我认为如果设计师想要,他们可以添加一个不带参数的重载:
static <T> Comparator<T> nullsFirst() // note: not legal
与使用nullsFirst(naturalOrder())
相同。但他们没有,所以你不能那样用它。
答案 1 :(得分:19)
尝试:
final Comparator<Persona> comparator =
comparing(Persona::getName, nullsFirst(naturalOrder()));
答案 2 :(得分:3)
我有一份员工名单,其中包含姓名和身份的学生。
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);
}
}
}
以
生成输出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]