实战小技巧7:排序比较要慎重

简介: 今天介绍的又是一个非常非常基本的基本知识点,为啥要单独拎出来?还是因为这个东西虽然非常简单,但是很容易掉坑,我已经遇到几次不严谨的写法了

今天介绍的又是一个非常非常基本的基本知识点,为啥要单独拎出来?还是因为这个东西虽然非常简单,但是很容易掉坑,我已经遇到几次不严谨的写法了


1. Comparator 与 Comparable



输掉排序,这两个接口好像不太容易绕过去,我们简单介绍下它们的区别


  • 如果你有一个类,希望支持同类型的自定义比较策略,可以实现接口Compareable
  • 如果某个类,没有实现Compareable接口,但是又希望对它进行比较,则可以自自定义一个Comparator,来定义这个类的比较规则


通过一个简单的实例进行演示说明

public static class Demo implements Comparable<Demo> {
    int code;
    int age;
    public Demo(int code, int age) {
        this.code = code;
        this.age = age;
    }
    @Override
    public int compareTo(Demo o) {
        if (code == o.code) {
            return 0;
        } else if (code < o.code) {
            return -1;
        } else {
            return 1;
        }
    }
    @Override
    public String toString() {
        return "Demo{" +
                "code=" + code +
                ", age=" + age +
                '}';
    }
}
复制代码


上面的实现中,重点关注 Demo类,实现了Comparable接口,因此可以直接调用list.sort(null)来进行比较;


但是如果我们现在需求改变了,希望实现针对demo类的age字段,进行升序排列,那么就可以利用Comparator来实现了


@Test
public void testDemoSort() {
    List<Demo> list = new ArrayList<>();
    list.add(new Demo(10, 30));
    list.add(new Demo(12, 10));
    list.add(new Demo(11, 20));
    // 默认根据 code 进行升序比较
    list.sort(null);
    System.out.println("sort by code: " + list);
    list.sort(new Comparator<Demo>() {
        @Override
        public int compare(Demo o1, Demo o2) {
            if (o1.age == o2.age) {
                return 0;
            } else if (o1.age < o2.age) {
                return -1;
            } else {
                return 1;
            }
        }
    });
    System.out.println("sort by age: " + list);
}
复制代码


输出结果如下

sort by code: [Demo{code=10, age=30}, Demo{code=11, age=20}, Demo{code=12, age=10}]
sort by age: [Demo{code=12, age=10}, Demo{code=11, age=20}, Demo{code=10, age=30}]
复制代码


2. 踩坑预告



再上面的compare方法实现中,我们可以发现里面的实现有点不太美观,我们最终的目的是什么?


  • 如果左边的小于右边的,返回 -1
  • 如果左边的大于右边的,返回 0
  • 如果左边的等于右边的,返回 1


基于此,经常可以看到的实现如下

list.sort(new Comparator<Demo>() {
    @Override
    public int compare(Demo o1, Demo o2) {
       return o1.age - o2.age;
    }
});
复制代码


上面这个实现虽然简洁了,但是有一个致命的问题,可能溢出!!!


所以请注意,千万千万不要用上面这种写法


那么有没有更优雅的方式呢?


  • 有,使用基础类的compare方法
list.sort(new Comparator<Demo>() {
    @Override
    public int compare(Demo o1, Demo o2) {
       return Integer.compare(o1.age, o2.age);
    }
});
复制代码


上面这一段代码,再jdk1.8中,可以简化为下面一句

list.sort(Comparator.comparingInt(o -> o.age));
复制代码


再扩展一下,如果希望倒排呢?


  • 第一种实现方式,调换位置
  • Jdk1.8方式,使用负数
list.sort(new Comparator<Demo>() {
    @Override
    public int compare(Demo o1, Demo o2) {
       return Integer.compare(o2.age, o1.age);
    }
});
list.sort(Comparator.comparingInt(o -> -o.age));
复制代码


3. 小结



今天主要介绍的知识点是排序,再我们日常使用中,如果一个类希望支持排序,最好的方式就是让它实现Comparable接口,然后自定义排序方式


这样再容器中,如果需要排序,直接调用 list.sort(null) 或者 CollectionUtils.sort(list)


如果目标类没有实现排序接口,或者希望使用另外一种排序方式,则通过自定义的Comparator来实现


最后关于compare方法的实现,设计到两个类的比较,这种最终的落脚地,多半是基础类型的比较


  • o1 与 o2 比较,返回负数,则最终的结果中o1再前面(即升序排列)
  • 不要直接使用 o1-o2会溢出,推荐使用 Integer.compare(o1, o2);



相关文章
|
1月前
|
SQL 关系型数据库 MySQL
在日常工作中怎么做MySQL优化的?
在日常工作中怎么做MySQL优化的?
|
3月前
|
SQL 关系型数据库 数据库
明明加了唯一索引,为何还有重复数据?技术深度剖析
【8月更文挑战第19天】在数据库管理和优化的道路上,唯一索引(Unique Index)是保障数据完整性和准确性的重要工具。然而,在实际应用中,不少开发者会遇到这样的困惑:明明已经为某个字段或字段组合加上了唯一索引,为何还会出现重复数据的情况?本文将深入探讨这一现象背后的原因,并提供相应的解决方案,帮助你在工作学习中更好地理解和应用唯一索引。
58 0
|
6月前
R语言表与因子(详细知识点,深入知识点后续会补充!)
R语言表与因子(详细知识点,深入知识点后续会补充!)
46 2
|
6月前
|
存储 算法 关系型数据库
MySQL怎样处理排序⭐️如何优化需要排序的查询?
MySQL怎样处理排序⭐️如何优化需要排序的查询?
|
6月前
|
自然语言处理 关系型数据库 MySQL
一文明白MySQL索引的用法及好处
一文明白MySQL索引的用法及好处
77 0
|
6月前
|
分布式计算 JavaScript 前端开发
给大家讲讲过滤查询的思路(一点就通)
给大家讲讲过滤查询的思路(一点就通)
57 1
|
搜索推荐
面试核心精简-各种排序算法(临时抱佛脚系列)
面试核心精简-各种排序算法(临时抱佛脚系列)
|
存储 SQL 关系型数据库
覆盖索引这回事算是整明白了
覆盖索引这回事算是整明白了
266 0
覆盖索引这回事算是整明白了
|
SQL 自然语言处理 关系型数据库
索引优化答疑补充和总结口诀|学习笔记
快速学习索引优化答疑补充和总结口诀
182 0
|
存储 缓存 算法
【肝帝一周总结:全网最全最细】☀️Mysql 索引数据结构详解与索引优化☀️《❤️记得收藏❤️》
【肝帝一周总结:全网最全最细】☀️Mysql 索引数据结构详解与索引优化☀️《❤️记得收藏❤️》
113 0
【肝帝一周总结:全网最全最细】☀️Mysql 索引数据结构详解与索引优化☀️《❤️记得收藏❤️》