Java 8 Comparator nullsFirst naturalOrder 混淆

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26350996/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 02:19:11  来源:igfitidea点击:

Java 8 Comparator nullsFirst naturalOrder confused

javastringsortingjava-8comparator

提问by chiperortiz

this may be a simple question but I would like to understand it clearly...

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

I have a code like this:

我有一个这样的代码:

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

And I am testing this code:

我正在测试这段代码:

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

This shows the following results:

这显示了以下结果:

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}

These results are OK with me but I have a problem understanding.

这些结果对我来说没问题,但我的理解有问题。

When I ignore the new Persona(5,null)object and I pass the comparator:

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

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

It works like a charm. My sorting is by natural order of name property. The problem arises when I add the object with name=null, I just thought I would need my comparator like this.

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

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

My thought was erroneous: "OK, when name is non-null, they are sorted in natural order of name, just like the previous comparator, and if they are nullthey will be first but my non-null names will still be sorted in natural order".

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

But the right code is this:

但正确的代码是这样的:

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

I don't understand the parameter to nullsFirst. I just thought the natural order of namewould explicitly [default] even handle nullvalues.

我不明白的参数nullsFirst。我只是认为natural order of name会明确 [default] 甚至处理null值。

But the docs say:

但是文档说:

Returns a null-friendly comparator that considers nullto be less than non-null. When both are null, they are considered equal. If both are non-null, the specified Comparatoris used to determine the order. If the specified comparator is null, then the returned comparator considers all non-null values to be equal.

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

This line: "If both are non-null, the specified Comparatoris used to determine the order."

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

I am confused when and how the natural order should be explicitly set or when they are inferred.

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

采纳答案by ajb

The "natural order" comparator, which is what you get when you use comparingwith only one parameter, does nothandle nulls. (I'm not sure where you got the idea that it did.) The "natural order" of a Comparableclass is defined by the compareTo()method, which is used like this:

“自然秩序”比较,这是你当你使用comparing,只有一个参数,它处理空值。(我不确定你从哪里得到它的想法。)类的“自然顺序”Comparable是由compareTo()方法定义的,它的用法如下:

obj1.compareTo(obj2)

Obviously this won't work if obj1is null; for String, it will also throw an exception if obj2is null.

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

The naturalOrder()method returns a Comparatorthat compares two objects. The javadocexplicitly says that this comparator throws NullPointerExceptionwhen comparing null.

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

The nullsFirst()method (and nullsLast()similarly) basically transforms a Comparatorto a new Comparator. You put in a comparator that may throw an exception if it tries to compare null, and it spits out a new comparator that works the same way except that it allows null arguments. So that's why you need a parameter to nullsFirst--because it builds a new comparator on top of an existing comparator, and you tell it what the existing comparator is.

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

So why doesn't it give you the natural order if you leave out the parameter? Because they didn't define it that way. nullsFirstis defined in the javadocto take a parameter:

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

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

I think that if the designers wanted to, they could have added an overload that takes no parameters:

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

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

that would be the same as using nullsFirst(naturalOrder()). But they didn't, so you can't use it like that.

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

回答by zgmnkv

Try:

尝试:

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

回答by Nikhil Kumar K

I have a list of Employee with Student with name and id ..

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


    }

}

Produces output as

产生输出为

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]