Java排序之Comparable和Comparator比较器详解

 更新时间:2024年01月08日 08:46:26   作者:nsnsttn  
这篇文章主要介绍了Java排序之Comparable和Comparator比较器详解,Comparable<T>是内部比较器,Comparator<T>是外部比较器,最推荐使用Comparator<T>接口排序,Comparator提供静态方法很方便,推荐使用,需要的朋友可以参考下

Comparable和Comparator比较器

Comparable<T>和 Comparator<T>这俩接口经常被使用,这里介绍下这俩是什么以及怎么用

Comparable<T>和Comparator<T>一般都是用来排序对象的,

Comparable<T>是内部比较器,Comparator<T>是外部比较器,直接上代码看例子

1.Comparable<T>

Comparable<T>内部比较器,故那个类需要排序能力就实现它

使用方式

1.如果我们想让List<SortA>按一定方式排序,可以将SortA实现 Comparable<SortA>接口,重写compareTo(SortA s)方法

@Data
public class SortA implements Serializable, Comparable<SortA>{
    
  	 @ApiModelProperty("名字")
    private String name;
    @ApiModelProperty("年龄")
    private Integer age;
    
    
    //自定义排序规则
    @Override
    public int compareTo(SortA o) {
        return  this.age - o.getAge(); //升序
        //return this.age.compareTo( o.getAge()); //升序
        //return o.getAge() - this.age; //倒序
        //return o.getAge().compareTo(this.age); //倒序
        //return -1; //自然排序的倒序
        //return 1 或 0; //自然排序
    }
}
public class 排序 {
    public static void main(String[] args) {
		//创造数据
        List<SortA> listA = new ArrayList<>();
        SortA a1 = new SortA();
        a1.setName("a张三");
        a1.setAge(18);
        SortA a2 = new SortA();
        a2.setName("c李四");
        a2.setAge(16);
        SortA a3 = new SortA();
        a3.setName("b王五");
        a3.setAge(17);
        listA.add(a1);
        listA.add(a2);
        listA.add(a3);
		//调用方法
        testComparable(listA);
    }
  
    public static void testComparable(List<SortA> listA) {
        //排序方法Collections.sort(List<T> list);
        //内部使用 Arrays.sort(a, (Comparator) c);    
        //所以如果数据是是数组,可以直接用Arrays.sort(数据)来排序
        Collections.sort(listA);
        System.out.println("Comparable排序:" + listA);
        //Comparable排序:[SortA(name=李四, age=16), SortA(name=王五, age=17), SortA(name=张三, age=18)]
    }
}

2.Comparator<T>

我们可以发现Comparable<T>代码侵入性比较强,而且不够灵活,我们同一对象每次排序的规则不可能都一样,那么就可以外部比较器Comparator<T>

使用方式

2.1 Comparator可以不由SortA实现,可以实现一个SortAComparator排序类

//注意泛型是需要排序的类SortA
public class SortAComparator implements Comparator<SortA> {

    /**
     *	compare()和compareTo()很像,返回值参照compareTo(),o1相当于this
     */
    @Override
    public int compare(SortA o1, SortA o2) {
        int sort = o1.getAge() - o2.getAge();
        return sort;
    }
}

2.2 Comparable是一个函数式接口,所以可以使用匿名内部类或者Lambda表达式(常用)来实现

甚至jdk8以后Comparable<T>提供了很多static方法直接供我们使用

2.3 直接上代码

public class 排序 {
    public static void main(String[] args) {
		//创造数据
        List<SortA> listA = new ArrayList<>();
        SortA a1 = new SortA();
        a1.setName("a张三");
        a1.setAge(18);
        SortA a2 = new SortA();
        a2.setName("c李四");
        a2.setAge(16);
        SortA a3 = new SortA();
        a3.setName("b王五");
        a3.setAge(17);
        listA.add(a1);
        listA.add(a2);
        listA.add(a3);
		//调用方法
        testComparator(listA);
    }
    public static void testComparator(List<SortA> listA) {
        //外部比较器,实现Comparator接口
        //1.SortAComparator实现Comparator接口
        listA.sort(new SortAComparator());
        System.out.println(listA);
        //2.使用匿名内部类或Lambda,表达式
        listA.sort(new Comparator<SortA>() {
            @Override
            public int compare(SortA o1, SortA o2) {
                //年龄倒序
                return o2.getAge() - o1.getAge();
            }
        });
        //3.使用匿名内部类或Lambda或Comparator的静态方法"
        //3.1按照名字正序排序
       	listA.sort(Comparator.comparing(SortA::getName));
        System.out.println(listA);
        //3.2按照名字倒序排序
        listA.sort(Comparator.comparing(SortA::getName).reversed());
        System.out.println(listA);
        listA.sort(Comparator.comparing(SortA::getName,Comparator.reverseOrder()));
        System.out.println(listA);
    }
}

注意多条件情况!!

reversed和Comparator.reverseOrder()反转顺序的时机不同

Comparator.reverseOrder()会立即对此属性排序

reversed()会得到左边的结果后在排序

所以

Comparator.reverseOrder()是只针对当前属性的反转,

reversed()会使左边所有排序反转,注意这一点就行了

上测试~~

public class 排序 {
public static void main(String[] args) {
        List<SortA> listA = new ArrayList<>();
        SortA a1 = new SortA();
        a1.setName("a");
        a1.setAge(18);
        SortA a2 = new SortA();
        a2.setName("a");
        a2.setAge(19);
        SortA a3 = new SortA();
        a3.setName("b");
        a3.setAge(17);
        SortA a4 = new SortA();
        a4.setName("c");
        a4.setAge(17);
        SortA a5 = new SortA();
        a5.setName("d");
        a5.setAge(15);
        listA.add(a1);
        listA.add(a2);
        listA.add(a3);
        listA.add(a4);
        listA.add(a5);
        moreComparator(listA);
    }
public static void moreComparator(List<SortA> listA){
        //1.name正序,name一样age正序
        listA.sort(Comparator.comparing(SortA::getName).thenComparing(SortA::getAge));
        System.out.println(listA);
        //2.name倒序,name一样age正序
        listA.sort(Comparator.comparing(SortA::getName).reversed().thenComparing(SortA::getAge));
        System.out.println(listA);     			listA.sort(Comparator.comparing(SortA::getName,Comparator.reverseOrder()).thenComparing(SortA::getAge));
        System.out.println(listA);
        //3.name倒序,name一样age倒序
        listA.sort(Comparator.comparing(SortA::getName).thenComparing(SortA::getAge).reversed());
        System.out.println(listA);
  listA.sort(Comparator.comparing(SortA::getName,Comparator.reverseOrder()).thenComparing(SortA::getAge,Comparator.reverseOrder()));
        System.out.println(listA);
        //4.name正序,name一样age倒序
        listA.sort(Comparator.comparing(SortA::getName).reversed().thenComparing(SortA::getAge).reversed());
        System.out.println(listA);
	listA.sort(Comparator.comparing(SortA::getName).thenComparing(SortA::getAge,Comparator.reverseOrder()));
        System.out.println(listA);
    }
}

注意对象为空或者属性为空的情况

public class 排序 {
    public static void main(String[] args) {
        List<SortA> listA = new ArrayList<>();
        SortA a1 = new SortA();
        a1.setName("a");
        a1.setAge(18);
        SortA a2 = new SortA();
        a2.setName("a");
        a2.setAge(19);
        SortA a3 = new SortA();
        a3.setName("b");
        a3.setAge(17);
        SortA a4 = new SortA();
        a4.setName("c");
        a4.setAge(17);
        SortA a5 = new SortA();
       // a5.setName("d");
        a5.setAge(15);
        listA.add(a1);
        listA.add(a2);
        listA.add(a3);
        listA.add(a4);
        listA.add(a5);
        listA.add(null);
        nullComparator(listA);	
	}
    //如果对象或者属性为空
    public static void nullComparator(List<SortA> listA){
        //1.如果对象为空
      listA.sort(Comparator.nullsFirst(Comparator.comparing(SortA::getName,Comparator.nullsFirst(Comparator.naturalOrder()))));
        System.out.println(listA);
        //2.如果name为空
        //自然排序
        listA.sort(Comparator.comparing(SortA::getName,Comparator.nullsFirst(Comparator.naturalOrder())));
        listA.sort(Comparator.comparing(SortA::getName,Comparator.nullsFirst(String::compareTo)));
        System.out.println(listA);
        //反转
        listA.sort(Comparator.comparing(SortA::getName,Comparator.nullsFirst(Comparator.reverseOrder())));
        System.out.println(listA);
    }
}

总结

  • Comparable<T>是内部比较器,Comparator<T>是外部比较器
  • 最推荐使用Comparator<T>接口排序
  • Comparator提供静态方法很方便,推荐使用,不了解的可以先去学习函数式接口、Lambda、方法引用
  • Comparator多条件排序时注意Comparator.reverseOrder()和reversed()的使用,
  • Comparator排序时注意对象和属性可能为空的情况,使用Comparator.nullsFirst()或者Comparator.nullsLast()

到此这篇关于Java排序之Comparable和Comparator比较器详解的文章就介绍到这了,更多相关Comparable和Comparator比较器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • DoytoQuery中的查询映射方案详解

    DoytoQuery中的查询映射方案详解

    这篇文章主要为大家介绍了DoytoQuery中的查询映射方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Java实现简单班级管理系统

    Java实现简单班级管理系统

    这篇文章主要为大家详细介绍了Java实现简单班级管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Java中并行执行任务的多种方式

    Java中并行执行任务的多种方式

    在Java编程中,经常会遇到需要并行执行任务的情况,特别是在处理大量数据或者需要异步处理的场景下,本文将介绍几种常用的并行执行任务的方式,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2024-04-04
  • SpringBoot的异常处理流程是什么样的?

    SpringBoot的异常处理流程是什么样的?

    今天给大家带来的是Java的相关知识,文章围绕着SpringBoot的异常处理流程展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • java用arraycopy实现多击事件

    java用arraycopy实现多击事件

    这篇文章主要介绍了java用arraycopy实现多击事件的多种方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • 关于最长递增子序列问题概述

    关于最长递增子序列问题概述

    本文详细介绍了最长递增子序列问题的定义及两种优化解法:贪心+二分查找和动态规划+状态压缩,贪心+二分查找时间复杂度为O(nlogn),通过维护一个有序的“尾巴”数组来高效地找到最长递增子序列,动态规划+状态压缩则通过状态压缩将空间复杂度优化至O(n)
    2025-02-02
  • 理解Java设计模式编程中的迪米特原则

    理解Java设计模式编程中的迪米特原则

    这篇文章主要介绍了Java设计模式编程中的迪米特原则,迪米特原则旨在降低类与类之间的耦合,需要的朋友可以参考下
    2016-02-02
  • Stream中的Peek操作代码

    Stream中的Peek操作代码

    这篇文章主要介绍了Stream中的Peek操作,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • JavaWeb实现压缩多个文件并下载实例详解

    JavaWeb实现压缩多个文件并下载实例详解

    本文通过实例代码给大家讲解了javaweb实现压缩多个文件并下载功能,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-07-07
  • iOS获取AppIcon and LaunchImage''s name(app图标和启动图片名字)

    iOS获取AppIcon and LaunchImage''s name(app图标和启动图片名字)

    这篇文章主要介绍了iOS获取AppIcon and LaunchImage's name(app图标和启动图片名字)的相关资料,非常不错,具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-08-08

最新评论