使用 Comparator 和 Comparable 对集合排序:如何轻松排序 Java 集合?

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

在 Java 中,排序是我们常常会遇到的操作。幸运的是,Java 提供了两种非常常用的方式来对集合进行排序:ComparableComparator。它们分别适用于不同的排序需求,并且各有其特点和使用场景。今天,我们将深入分析这两种排序机制,并通过代码示例帮助你理解如何灵活地对集合进行排序。

1. Comparable 接口

Comparable 接口是 Java 自带的用于对对象进行排序的机制。它允许对象按照自然顺序进行排序,通常用于当你希望一个类的实例对象在没有外部干预的情况下就能比较大小的情况。

1.1. Comparable 接口的定义

Comparable 接口只有一个方法 compareTo(),它定义了当前对象与传入对象的比较规则。

public interface Comparable<T> {
    int compareTo(T o);
}
  • 返回值:
    • 负数:当前对象小于传入对象
    • :当前对象等于传入对象
    • 正数:当前对象大于传入对象

1.2. Comparable 排序示例

假设我们有一个 Person 类,其中包含 nameage 两个属性,我们希望按照 age 从小到大进行排序。我们可以实现 Comparable 接口,并重写 compareTo() 方法。

import java.util.*;

class Person implements Comparable<Person> {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 实现 compareTo 方法,按 age 排序
    @Override
    public int compareTo(Person other) {
        return Integer.compare(this.age, other.age);
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}

public class ComparableExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        // 使用 Collections.sort 对集合进行排序
        Collections.sort(people);

        // 打印排序后的结果
        for (Person person : people) {
            System.out.println(person);
        }
    }
}

输出:

Bob: 25
Alice: 30
Charlie: 35

在上面的代码中,Person 类实现了 Comparable 接口,重写了 compareTo() 方法,按照 age 进行排序。当我们调用 Collections.sort() 方法时,集合就会按照 compareTo() 方法的逻辑进行排序。

2. Comparator 接口

Comparator 接口是 Java 提供的另一种排序机制,与 Comparable 不同,它并不改变对象本身,而是提供一个外部的比较器来定义排序规则。使用 Comparator,你可以在不修改对象类的情况下灵活地实现多种排序方式。

2.1. Comparator 接口的定义

Comparator 接口有两个重要的方法:

public interface Comparator<T> {
    int compare(T o1, T o2);
}
  • 返回值:
    • 负数o1 小于 o2
    • o1 等于 o2
    • 正数o1 大于 o2

2.2. Comparator 排序示例

如果我们希望对 Person 类按 name 字母顺序进行排序,而不影响按 age 排序的逻辑,我们可以使用 Comparator

import java.util.*;

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}

public class ComparatorExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        // 使用 Comparator 按 name 排序
        people.sort(new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                return p1.name.compareTo(p2.name);
            }
        });

        // 打印排序后的结果
        for (Person person : people) {
            System.out.println(person);
        }
    }
}

输出:

Alice: 30
Bob: 25
Charlie: 35

在这个例子中,我们没有修改 Person 类,而是创建了一个匿名 Comparator 类,在 compare() 方法中定义了按 name 排序的逻辑。使用 people.sort() 方法对列表进行了排序。

2.3. Comparator 使用 lambda 表达式

从 Java 8 开始,我们可以使用更简洁的方式来实现 Comparator,即通过 lambda 表达式。这样可以让代码更加简洁,减少冗余。

import java.util.*;

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}

public class ComparatorLambdaExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        // 使用 lambda 表达式按 name 排序
        people.sort((p1, p2) -> p1.name.compareTo(p2.name));

        // 打印排序后的结果
        for (Person person : people) {
            System.out.println(person);
        }
    }
}

输出:

Alice: 30
Bob: 25
Charlie: 35

通过 lambda 表达式,我们可以轻松实现按 name 排序,并且代码更加简洁。

2.4. 多种排序方式的组合

如果我们希望根据多个属性进行排序(例如先按 age 排序,如果 age 相同,再按 name 排序),可以使用 ComparatorthenComparing() 方法来组合多个排序条件。

import java.util.*;

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}

public class MultiComparatorExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 30));
        people.add(new Person("Dave", 25));

        // 按 age 排序,如果 age 相同,再按 name 排序
        people.sort(Comparator.comparingInt(Person::getAge)
                             .thenComparing(Person::getName));

        // 打印排序后的结果
        for (Person person : people) {
            System.out.println(person);
        }
    }
}

输出:

Bob: 25
Dave: 25
Alice: 30
Charlie: 30

通过 Comparator.comparingInt()thenComparing() 方法,我们实现了先按 age 排序,再按 name 排序的功能。

3. ComparableComparator 的比较

特性ComparableComparator
排序方式自然排序(类内部实现)外部比较器定义(灵活自定义排序规则)
实现的接口方法compareTo()compare()
修改对象类需要修改对象类无需修改对象类
使用场景类本身有天然的排序顺序时需要多种排序规则或对象类无法修改时

4. 总结

  • Comparable:适用于类本身已经有了自然排序顺序的情况,且仅需要一种排序方式。通过实现 compareTo() 方法,我们可以定义类的默认排序规则。
  • Comparator:适用于需要多种排序方式的场景,或者当我们不能修改原始类时。通过 compare() 方法,可以定义任意排序逻辑,甚至可以组合多个比较器进行复合排序。

在实际开发中,我们可以根据具体需求灵活选择使用 Comparable 还是 Comparator,并通过 Java 8 引入的 lambda 表达式来简化代码。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值