Java排序之Comparable和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比较器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
理解 MyBatis 是如何在 Spring 容器中初始化的
这篇文章主要介绍了理解 MyBatis 是如何在 Spring 容器中初始化的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-11-11
最新评论