Java如何使用排序

排序的介绍

为什么需要排序

在开发中,需要对一组对象进行排序,是非常常见的业务需求。排序可以让数据更加有序,便于查找和操作,以及数据的统计和分析。

在Java中,可以使用Arrays类对数组提供的方法进行排序,或使用Collections类对集合进行排序

可以通过Comparable自然排序和Comparator定制排序进行实现

使用Arrays类对数组进行排序

// 没传入compartor比较器,内部会使用comparable比较器
public static void sort(Object[] a) {
    if (LegacyMergeSort.userRequested)
        legacyMergeSort(a);
    else
        ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}

public static <T> void sort(T[] a, Comparator<? super T> c) {
    if (c == null) {
        sort(a); // 如果comparator是空的,就调用上面的sort方法
    } else {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, c);
        else
            TimSort.sort(a, 0, a.length, c, null, 0, 0);
    }
}

通过源码发现,我们想要对Object进行排序,可以使用java提供的上面两个接口,一个是直接传入对象数组,另一个是传入对象数组和Comparator比较器。

  • 直接传入对象数组的方式为使用自然排序
  • 传入Comparator比较器使用的是定制排序
  • 如果类中既实现了comparable,在调用sort时又传入comparator比较器,会优先使用comparator定制排序。

如果不传入Comparator比较器,就会使用comparable比较器进行排序,此时就会看你是否实现了comparable比较器,如果没实现comparable接口,就会出现类型转换异常。因为在源码中会将实体类转换为comparable,具体可以自行查看源码深入探究。

使用Collections类对集合进行排序

源码如下

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

通过源码可以发现Collections.sort 提供了两个接口,一个是直接传我们想要排序的List,另一个是传传我们想要排序的List和Comparator比较器。

再继续深入代码,发现Collections排序的底层是基于Arrays的

在这里插入图片描述

为什么叫自然排序和定制排序

自然排序

自然排序(Natural Ordering)也叫常规排序,是指使用Java对象默认的排序规则进行排序,例如整数默认按照数值大小升序排序,字符串默认按照字典序升序排序。
Comparable接口则提供了一种自然排序的方式,它只定义了一种比较规则,且只能在同一个对象之间进行排序,不能定制化排序。说白了就是不能玩花活。

定制排序

定制排序(Customized Ordering)是指使用自己定制的排序规则进行排序,它比较灵活,例如按照字符串长度升序排序,或者按照对象某个属性的大小排序。

Comparator接口提供了一种定制排序的方式,它可以定义多种不同的排序规则,程序员可以根据需要选择不同的比较器实现类。

使用Comparable自然排序

使用自然排序,就是在类中实现comparable接口,然后通过Arrays.sort(T[] arr) 或 Collections.sort(List list)的方式进行排序,需要注意的是,如果类中没实现comparable接口,就会出现类型转换异常。因为在源码中会将实体类转换为comparable。

具体可以自行查看源码深入探究。

举例:通过Comparable自然排序将Person类中的age进行排序

自然排序使用方法:按照 age 属性的自然排序排序,实现 Comparable 接口并重写 compareTo 方法。

示例代码如下:

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

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public int compareTo(Person other) {
        return Integer.compare(this.age, other.age);
    }
}

直接调用 Collections.sort 方法就可以对 Person 对象集合进行自然排序,如下所示:

List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 30));
Collections.sort(people);

使用Comparator定制排序

举例:通过Comparator定制排序将Person类中的age进行升序排序,对编号进行降序排序

定制排序使用方法:

  1. 显示定义一个比较器类实现Comparator接口,将比较器对象传入sort方法中
  2. 直接在Collections.sort中编写comparator的内部类实现

我们采用第二种方法,

假设我们有一个名为Person的类,其中有三个属性:姓名、年龄、编号。我们想对年龄age进行升序排序,对编号number进行降序排序

@Data
public class Person {
    private String name;
    private int age;
	  private int number;

}

现在我们有一个List对象,其中包含了若干个Person对象,我们可以使用Collections.sort()方法对它们进行排序:

List<Person> personList = new ArrayList<>();
personList.add(new Person("Alice", 20, 1000));
personList.add(new Person("Bob", 18,2000));
personList.add(new Person("Charlie", 25,4000));
personList.add(new Person("David", 25,3000));

Collections.sort(personList, new Comparator<Person>() {
			@Override
			public int compare(Person o1, Person o2) {
				if (o1.getAge().equals(o2.getAge())){
					return o2.getNumber() - o1.getNumber();
				}
				return o1.getAge() - o2.getAge() ;
			}
		});

System.out.println(personList);

输出结果为:

Student{name='Bob', age=18, number=2000}
Student{name='Alice', age=20, number=1000}
Student{name='Charlie', age=25, number=4000}
Student{name='David', age=25, number=3000}

Comparator和Comparable的区别

相同点: 在Java中,可以使用ComparatorComparable接口来定义对象的排序方式。

不同点:

  1. 内部接口和外部接口
    • Comparable`接口是Java中的内部排序接口,它需要在类中定义类的自然排序顺序
    • Comparator接口是Java中的外部排序接口,它使用外部比较器定制排序顺序,而不修改类本身
  2. 比较复杂度不同
    • 自然排序只能对自己对象间的值进行一个简单比较
    • 定制排序可以根据业务需求,实现复杂的排序规则,不仅能比较值,也可以比较长度等,也可以对不同对象的内容进行比较

使用场景

虽然comparator和comparable在功能上没什么区别,都可以实现排序,但是他们在使用场景上还是有区别的

  • 使用 Comparable

    • 当对象有一个明显自然的排序方式。
    • 希望所有地方默认使用这种排序方式(起到排序复用的效果)。
  • 使用 Comparator

    当对象需要多种排序方式,也就是说可以玩花活,当排序逻辑不属于对象的主要功能,而是属于某个特定的排序业务需求,而且对于这个排序,在多个业务中又有着不同的排序需求,其他场景对于该对象又会有其他的排序需求,那就使用comparator吧!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值