【问题标题】:Java Comparator with null fields具有空字段的 Java 比较器
【发布时间】:2019-06-14 12:58:57
【问题描述】:

我有一个实体列表Entity,其中包含idcreatedDate 字段。我想将它们排序如下:

  • 更高id第一
  • 如果id null,则最近的createdDate 优先

我尝试了以下失败,因为当id 为空时它会抛出NullPointerException

Comparator comp = Comparator
                .nullsFirst(Comparator.comparing(e -> ((Entity) e).getId()))
                .thenComparing(e -> ((Entity e).getCreatedDate())
                .reversed();
entities.stream().sorted(comp).findFirst();

就我所见,Comparator.nullsFirst 在实体为空时处理,而不是在要比较的字段为空时处理。我该如何处理这种情况?

【问题讨论】:

    标签: java sorting java-8 java-stream


    【解决方案1】:

    我认为您正在寻找这样的比较器,使用 Comparator.nullsLast

    Comparator<MyClass> comparator = Comparator.comparing(MyClass::getId, Comparator.nullsLast(Comparator.reverseOrder()))
                    .thenComparing(MyClass::getCreateDate);
    

    测试它的代码:

    List<MyClass> list = new ArrayList<>();
    
    list.add(new MyClass(null, LocalDate.now()));
    list.add(new MyClass(4L, LocalDate.now()));
    list.add(new MyClass(2L, LocalDate.now()));
    list.add(new MyClass(4L, LocalDate.now().plusDays(1)));
    list.add(new MyClass(null, LocalDate.now().plusDays(1)));
    
    Comparator<MyClass> comparator = Comparator.comparing(MyClass::getId, Comparator.nullsLast(Comparator.reverseOrder()))
                    .thenComparing(MyClass::getCreateDate);
    
    list.stream().sorted(comparator).forEach(myClass -> System.out.println(myClass.id + " " + myClass.createDate));
    

    输出是:

    4 2019-06-14
    4 2019-06-15
    2 2019-06-14
    null 2019-06-14
    null 2019-06-15
    

    如果您希望 nulls 成为第一个,只需将 nullsLast 更改为 nullsFirst

    【讨论】:

      【解决方案2】:

      扩展@Mena 的评论:

      java.util.Collections.sort(entities, new Comparator<Entity>(){
         @Override
         public int compare(Entity ent1, Entity ent2) {
           Object id1=ent1.getId();
           Object id2 = ent2.getId();
           if (id1!=null && id2!=null)
           {
             return id2.compareTo(id1);
           }
           else
           {
             Date d1 = ent1.getCreatedDate();
             Date d2 = ent2.getCreatedDate();
             return d2.compareTo(d1);
           }
         }
      });
      

      【讨论】:

      • nulls 怎么会被推到这里来?
      • 如果 id1 或 id2 为空,则比较日期。
      • 考虑id1nullid2不是的情况?
      • 这种情况下的结果应该是什么?从问题中我推断出,在这两种情况下,日期都进行了比较
      【解决方案3】:

      使用Object类的nonNull方法,或许可以解决。

      Comparator comp = Comparator
                  .nullsFirst(Comparator.comparing(e -> nonNull(((Entity) e).getId()))
                  .thenComparing(e -> ((Entity e).getCreatedDate())
                  .reversed();
      entities.stream().filter(comp).findFirst();
      

      【讨论】:

        【解决方案4】:

        我很少使用 lambda,但我可以帮助您使用比较器。

        Comparator<Entity> cmp = new Comparator<Entity>() {
        
                @Override
                public int compare(Entity e1, Entity e2) {
                    if(e1.id!=null && e2.id!=null){
                        return e2.id - e1.id;
                    }
                    return e1.createdDate - e2.createdDate;
                    //createdDate should be an Integer field otherwise convert it to integer somehow.
                }
        
            };
            //To use this comparator
            Collections.sort(your_list,cmp);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-24
          • 2021-09-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多