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 name
的natural 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 super T> 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]