【问题标题】:Java 8 Comparator chaining with a reverse on single propertyJava 8 比较器链接与单个属性的反向
【发布时间】:2018-06-18 19:37:47
【问题描述】:

我正在使用ComparatorStudent 对象列表进行排序。

我想反转id 属性的排序,但使用reverse() 方法将其应用于整个排序。

如何让它只在id上发生?

到目前为止,这是我的代码:

 public List<Student> getStudents(List<String> events) {
    Comparator<Student> comparatorStudents = Comparator.comparing(Student::getCGPA).thenComparing(Student::getName)
      .thenComparingInt(Student::getID).reverse();
    List<Student> students = new ArrayList<Student>();
    //Filling students
    Collections.sort(students, comparatorStudents);
    return students;
  }

【问题讨论】:

    标签: java sorting java-8 comparator


    【解决方案1】:

    将最后一位更改为:

    .thenComparing(Student::getID, Comparator.reverseOrder())
    

    或者,如果您想避免自动装箱:

    .thenComparing(Comparator.comparingInt(Student::getID).reversed())
    

    【讨论】:

    • 能否详细说明“避免自动装箱”
    • @MartinDinev 第一个变体接受Function&lt;Student, Integer&gt;,这意味着它将Student.getID() 返回的int 转换为Integer。另一方面,Comparator.comparingInt() 接受 ToIntFunction,它只使用原语进行比较。
    【解决方案2】:

    reversed()的调用放到thenComparing里面:

    public List<Student> getStudents(List<String> events) {
        Comparator<Student> comparatorStudents = Comparator.comparing(Student::getCGPA)
           .thenComparing(Student::getName)
           .thenComparing(Comparator.comparingInt(Student::getID).reversed());
        List<Student> students = new ArrayList<Student>();
        //Filling students
        Collections.sort(students, comparatorStudents);
        return students;
    }
    

    【讨论】:

      【解决方案3】:

      我喜欢使用Guava's Ordering class 进行几乎所有的排序。这里有很好的记录:https://github.com/google/guava/wiki/OrderingExplained

      除其他外,我喜欢Ordering,因为:

      1. 它使用“流利的”API。
      2. Orderings 实现 Comparable,因此可以在任何可以使用 Comparable 的地方使用。
      3. 它们自然是线程安全的(这意味着您可以将它们声明为静态常量并在任何地方重用单个实例)。

      在你的情况下,我会编写如下代码:

      private static final Ordering<Student> BY_GPA = Ordering.natural().onResultOf(Student::getCGPA);
      private static final Ordering<Student> BY_NAME = Ordering.nautural().onResultOf(Student::getName);
      private static final Ordering<Student> BY_ID_DESCENDING = Ordering.natural().reverse().onResultOf(Student::getID);
      
      // I spent approximately zero time coming up with a good name for this constant
      public static final Ordering<Student> STUDENT_ORDER = BY_CPA.compound(BY_NAME).compound(BY_ID_DESCENDING);
      
      public List<Student> getStudents(List<String> events) {
          List<Student> students = new ArrayList<Student>();
          //Filling students
          Collections.sort(students, STUDENT_ORDER);
          return students;
      }
      

      就个人而言,我通常会在 Student 类中声明这些常量,这样任何与 Student 对象交互的任何地方都可以轻松找到并重用他们对它们进行排序所需的内容。在这种情况下,我可能会命名公共常量 DEFAULT_ORDER 或类似的名称,但如果没有更多上下文,我不确定按 GPA 排序是否是您真正想要的默认值。

      您绝对不必声明四个单独的常量——三个私有常量绝对可以内联声明。我喜欢这样做,因为我发现它提高了可读性。

      另外:我不确定您在复制方面的需求是什么,但如果保证学生是唯一的并且您很好地实现了 equalshashCode,我鼓励您使用 @ 987654330@。这样,它们会在您添加到集合时进行排序,并且如果您修改集合,它们会自动保持这种状态。

      【讨论】:

      • 我要补充一点,我从 Java 6 开始就一直这样做,并且没有正确地了解 Java 8 中关于比较器的新功能(看起来花了很多时间来自番石榴的影响!)。我遵从其他答案,这些答案是在我写我的时候出现的。 :)
      • 非常有趣的做事方式。
      猜你喜欢
      • 2017-06-26
      • 2016-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多