四时宝库

程序员的知识宝库

java8精华-函数式编程-完结(十)(java8函数编程)

在上一篇文章中,compare和comparator我们已经了解了 Comparable 和 Comparable 接口以及它们对应的 lambda 表达式。

我们还了解了 Comparator 接口中的两个方法:comparing() 和 thenComparing()。这两种方法允许我们以更具声明性的方式进行编程。

首先,让我们看下下面的 Student 类。

class Student {
    private final int id;
    private final String name;
    private final String course;
    private final int deptNo;

    Student(int id, String name, String course, int deptNo) {
        this.id = id;
        this.name = name;
        this.deptNo = deptNo;
        this.course = course;
    }

    public int getId() { return id; }
    public String getName() { return name; }
    public int getDeptNo() { return deptNo; }
    
    public String toString() {
     return String.format("%d,%s,%s,%d", id, name, course, deptNo);
    }
}

假设我们已将上面的内容转换为 List<Student> 对象。

现在我们要对这个列表进行排序,首先对具有相同 DEPTNO 的所有学生进行排序,然后如果两个学生具有相同的DEPTNO,则必须按 ID 升序对他们进行排序。

我们可以简单地将 lambda 写成如下所示。

students.sort((s1, s2) -> {
    int diff = s1.getDeptNo() - s2.getDeptNo();
    return diff == 0 ? s1.getId() - s2.getId() : diff;
});

但是如果我们希望它们按降序排列怎么办?

我们必须使用 lambda 编写另一个排序逻辑,如下所示。

students.sort((s1, s2) -> {
    int diff = s2.getDeptNo() - s1.getDeptNo();
    return diff == 0 ? s2.getId() - s1.getId() : diff;
});

问题是如果我们想要另一种排序方式,我们必须编写另一个 lambda。

有一种更好、更具声明性的方法,就是可以使用 Comparator.comaparing() 和 Comparator.thenComparing() 来完成此操作。

Comparator<Student> deptWiseStdIdComparator = 
             Comparator.comparing(Student::getDeptNo) 
                       .thenComparing(Student::getId) 
students.sort(deptWiseStdIdComparator);

我故意把它分成两行更容易理解。

Comparator.comparing(Student::getDeptNo):这将返回一个比较部门编号的Comparator。

Comparator.thenComparing(Student::getId):这会返回一个 Comparator,它是与此关联的Comparator和作为参数提供给它的函数表达式的组合。

如果按降序排列呢?这样做的好处是我们不必编写另一个逻辑。我们只需要将其反转,如下所示

Comparator<Student> revDeptWiseStdIdComparator = 
                              deptWiseStdIdComparator.reversed();

returned() 方法翻转整个排序。

但我们可以说我们不想要这样。我们想要的是部门应按升序显示,但学生 ID 应按降序显示。请记住,reverse() 方法会将整个排序颠倒过来。

为了实现这一点,我们应该通过如下拆分语句来实现这一点。

students.sort(Comparator
        .comparing(Student::getDeptNo)
        .reversed()
        .thenComparing(Student::getId));
students.forEach(System.out::println);

首先,我们使用反向的部门编号Compartor,然后使用 ID 比较器,并使用 thenComparing() 将它们连接起来。

如果我们想要相反的情况,即按部门升序但按学生降序,我们该怎么写呢?。你可能会想到这样写?

students.sort(Comparator
        .comparing(Student::getDeptNo)
        .thenComparing(Student::getId)
        .reversed());
students.forEach(System.out::println);

但这并没有给我们带来我们想要的结果。最后使用reverse()会将整个排序颠倒过来。

非常重要

如果降序比较位于最后,那么我们应该谨慎使用reverse()方法,因为它会将整个排序颠倒过来。

如果您想在链的末尾使用reverse(),那么可以将整个排序视为相反的方式。

我们必须编写与我们想要的相反的整个排序,然后使用reverse()来否定整个排序。

students.sort(Comparator
        .comparing(Student::getDeptNo)
        .reversed()
        .thenComparing(Student::getId)
        .reversed());
students.forEach(System.out::println);

我们只需要反转它,所以我们使用了reverse()。

或者您可以拆分Comparator并按如下所述进行操作。

Comparator<Student> deptWiseComparator = 
             Comparator.comparing(Student::getDeptNo);
Comparator<Student> stdIdRevComparator = 
             Comparator.comparing(Student::getId).reversed();
students.sort(deptWiseComparator.thenComparing(stdIdRevComparator));
students.forEach(System.out::println);

这就是本文的全部内容。至此,我们这个系列就可以结束了。

总结

  1. comparingthenComparing方法提供了一种更具声明性的编写比较代码的方式。
  2. 如果我们想反转特定的比较,那么我们可以简单地调用reversed()
  3. 在我们想要的任何比较中,如果reversed()在末尾,那么我们必须考虑与我们想要的完全相反的比较,来获得一致的结果。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接