【问题标题】:Java 8 Comparator nullsFirst naturalOrder confusedJava 8 比较器 nullsFirst naturalOrder 混淆
【发布时间】:2014-12-08 16:01:27
【问题描述】:

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

我有这样的代码:

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

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

但正确的代码是这样的:

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

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

但是文档说:

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

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

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

【问题讨论】:

  • 注意“如果指定的比较器是null,那么返回的比较器认为所有非空值都是相等的。” 也就是说,你可以做@987654341 @;然而,它只是将空值排序到前面,而不对非空值进行排序。文档实际上解释得很好。
  • @chiperotiz 那么你最终是如何解决的呢?你能先按空值排序,然后按自然顺序排序吗?
  • 是的,使用此代码final Comparator&lt;Persona&gt;comparator = comparing(Persona::getName,nullsFirst(naturalOrder()));

标签: java string sorting java-8 comparator


【解决方案1】:

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

obj1.compareTo(obj2)

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

naturalOrder() 方法返回一个比较两个对象的Comparatorjavadoc 明确表示此比较器在比较 null 时会抛出 NullPointerException

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

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

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

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

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

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

【讨论】:

  • 你好 ajb 我从没想过唯一的参数比较器是处理空值。我只是认为 nullsFirst() 方法会将空值放在首位,非空值将按自然顺序排序好吧......但正如你所说static &lt;T&gt; Comparator&lt;T&gt; nullsFirst() // note: not legal simple 是不合法的。我只是觉得会很好,因为你说没有参数的 nullFirst 应该是默认的 naturalOrder() .. 谢谢。
【解决方案2】:

试试:

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

【讨论】:

    【解决方案3】:

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

    生成输出为

    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]
    

    【讨论】:

      猜你喜欢
      • 2012-08-18
      • 1970-01-01
      • 2017-01-24
      • 1970-01-01
      • 2017-10-28
      • 2015-11-02
      • 2014-06-03
      • 2019-12-29
      • 2016-03-19
      相关资源
      最近更新 更多