Java 比较器Comparator和Comparable的使用和区别

简介: 一、参考1、【java】Comparator的用法2、Java 中 Comparable 和 Comparator 比较二、知识点1、使用场景:排序、分组2、使用方法:  2.1 、Arrays.sort(T[],Comparator

一、参考

1、【java】Comparator的用法
2、Java 中 Comparable 和 Comparator 比较

二、知识点

1、使用场景:排序、分组
2、使用方法:

  2.1 、Arrays.sort(T[],Comparator<? super T> c);
  2.2、 Collections.sort(List<T> list,Comparator<? super T> c);

3、区别:

  3.1 、Comparator相当于给一个数组或列表新增一种比较方式
  3.2 、Comparable是接口需要被类继承的,相当于本身这个数组或者列表及类就有这种比较方式。后面有详细是有案例

三、案例

1、OrderBean订单类

 1.1、继承了Comparable这个借口,有个简单的比较,升序的

//订单
public class OrderBean implements Comparable<OrderBean>{
    private int id;         //id
    private String cdate;   //创建时间
    private String product; //产品名称
    private int weight;     //重量
    private long price;     //价格
    
    public OrderBean(int id, String cdate, String product, int weight, long price) {
        this.id = id;
        this.cdate = cdate;
        this.product = product;
        this.weight = weight;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getCdate() {
        return cdate;
    }

    public void setCdate(String cdate) {
        this.cdate = cdate;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public long getPrice() {
        return price;
    }

    public void setPrice(long price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "\nOrder_"+id+": ["
                + "cdate="+cdate+", "
                + "product="+product+", "
                + "weight="+weight+" KG, "
                + "price="+price+" RMB, "
                + "]";
    }

    /**
     * 按照weight升序
     * sort的话默认调用
     * */
    public int compareTo(OrderBean o) {
        return weight - o.getWeight();
    }
}
2、Comparable接口使用

 2.1、如果bean类继承Comparable接口,那么它的集合使用Collections.sort(list);可以默认调用bean类中复写的compareTo这个方法,进行排序
 2.2、也可以使用compareTo单独比较两个类

private void testComparable() {
        System.out.println("\n\n testComparable()>>>");
        OrderBean order1 = new OrderBean(1,"2018-01-01","牛肉",10,300);
        OrderBean order2 = new OrderBean(5,"2018-01-01","怪兽肉",80,400);
        OrderBean order3 = new OrderBean(2,"2018-02-01","牛肉",100,300);
        OrderBean order4 = new OrderBean(9,"2018-03-01","唐僧肉",2,600);
        
        List<OrderBean> list = new ArrayList<OrderBean>();
        list.add(order1);
        list.add(order2);
        list.add(order3);
        list.add(order4);
        
        // weight升序排列
        Collections.sort(list);
        System.out.println("按照订单的weight升序排列:" + list);
        System.out.println("比较1和3:"+order1.compareTo(order3));
    }
 testComparable()>>>
按照订单的weight升序排列:[
Order_9: [cdate=2018-03-01, product=唐僧肉, weight=2 KG, price=600 RMB, ], 
Order_1: [cdate=2018-01-01, product=牛肉, weight=10 KG, price=300 RMB, ], 
Order_5: [cdate=2018-01-01, product=怪兽肉, weight=80 KG, price=400 RMB, ], 
Order_2: [cdate=2018-02-01, product=牛肉, weight=100 KG, price=300 RMB, ]]
比较1和3:-90
3、Comparator比较器的使用

 3.1、排序:大于、小于、等于
 3.2、分组:等于、不等于

private void testComparator() {
        System.out.println("\n\n testComparator()>>>");
        OrderBean order1 = new OrderBean(1,"2018-01-01","牛肉",10,300);
        OrderBean order2 = new OrderBean(5,"2018-01-01","怪兽肉",80,400);
        OrderBean order3 = new OrderBean(2,"2018-02-01","牛肉",100,300);
        OrderBean order4 = new OrderBean(9,"2018-03-01","唐僧肉",2,600);
        
        List<OrderBean> list = new ArrayList<OrderBean>();
        list.add(order1);
        list.add(order2);
        list.add(order3);
        list.add(order4);
        
        /**
         * ----------------排列-----------------
         * 大于、小于、等于
         * */
        //id降序排列
        Collections.sort(list, new Comparator<OrderBean>() {
            public int compare(OrderBean o1, OrderBean o2) {
                return o2.getId() - o1.getId();
            }
        });
        System.out.println("按照订单的id降序排列:"+list);
        
        
        //单价升序排列
        Collections.sort(list, new Comparator<OrderBean>() {
            public int compare(OrderBean o1, OrderBean o2) {
                return (int)(o1.getPrice()/o1.getWeight() - o2.getPrice()/o2.getWeight());
            }
        });
        System.out.println("按照订单的单价升序排列:"+list);
        System.out.println("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\");
        
        /**
         * ----------------分组-----------------
         * 等于、不等于
         * */
        List<List<OrderBean>> byDate = divider(list,new Comparator<OrderBean>() {
            public int compare(OrderBean o1, OrderBean o2) {
                return o1.getCdate().equals(o2.getCdate()) ? 0:1;
            }
        });
        for(int i=0;i<byDate.size();i++) {
            System.out.println("按照订单的cdate分组【"+i+"】:"+byDate.get(i));
        }
        
        
    }
testComparator()>>>
按照订单的id降序排列:[
Order_9: [cdate=2018-03-01, product=唐僧肉, weight=2 KG, price=600 RMB, ], 
Order_5: [cdate=2018-01-01, product=怪兽肉, weight=80 KG, price=400 RMB, ], 
Order_2: [cdate=2018-02-01, product=牛肉, weight=100 KG, price=300 RMB, ], 
Order_1: [cdate=2018-01-01, product=牛肉, weight=10 KG, price=300 RMB, ]]
按照订单的单价升序排列:[
Order_2: [cdate=2018-02-01, product=牛肉, weight=100 KG, price=300 RMB, ], 
Order_5: [cdate=2018-01-01, product=怪兽肉, weight=80 KG, price=400 RMB, ], 
Order_1: [cdate=2018-01-01, product=牛肉, weight=10 KG, price=300 RMB, ], 
Order_9: [cdate=2018-03-01, product=唐僧肉, weight=2 KG, price=600 RMB, ]]
\\\\\\\\\\\\\\\\\\
按照订单的cdate分组【0】:[
Order_2: [cdate=2018-02-01, product=牛肉, weight=100 KG, price=300 RMB, ]]
按照订单的cdate分组【1】:[
Order_5: [cdate=2018-01-01, product=怪兽肉, weight=80 KG, price=400 RMB, ], 
Order_1: [cdate=2018-01-01, product=牛肉, weight=10 KG, price=300 RMB, ]]
按照订单的cdate分组【2】:[
Order_9: [cdate=2018-03-01, product=唐僧肉, weight=2 KG, price=600 RMB, ]]

分组工具方法

/**
     * @author wujn
     * @Description:按条件分组
     * @param datas
     * @param c
     * 是否为同一组的判断标准 0 为同一组,1为不同组
     * @return
     */
    public static <T> List<List<T>> divider(Collection<T> datas, Comparator<? super T> c) {
        List<List<T>> result = new ArrayList<List<T>>();
        for (T t : datas) {
            boolean isSameGroup = false;
            for (int j = 0; j < result.size(); j++) {
                if (c.compare(t, result.get(j).get(0)) == 0) {
                    isSameGroup = true;
                    result.get(j).add(t);
                    break;
                }
            }
            if (!isSameGroup) {
                // 创建
                List<T> innerList = new ArrayList<T>();
                result.add(innerList);
                innerList.add(t);
            }
        }
        return result;
    }
目录
相关文章
|
5天前
|
Java
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别
|
13天前
|
Java
通过Java代码解释成员变量(实例变量)和局部变量的区别
本文通过一个Java示例,详细解释了成员变量(实例变量)和局部变量的区别。成员变量属于类的一部分,每个对象有独立的副本;局部变量则在方法或代码块内部声明,作用范围仅限于此。示例代码展示了如何在类中声明和使用这两种变量。
|
25天前
|
Java
Java基础之 JDK8 HashMap 源码分析(中间写出与JDK7的区别)
这篇文章详细分析了Java中HashMap的源码,包括JDK8与JDK7的区别、构造函数、put和get方法的实现,以及位运算法的应用,并讨论了JDK8中的优化,如链表转红黑树的阈值和扩容机制。
19 1
|
29天前
|
Java 编译器 C语言
【一步一步了解Java系列】:探索Java基本类型与C语言的区别
【一步一步了解Java系列】:探索Java基本类型与C语言的区别
36 2
|
29天前
|
存储 缓存 Java
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
31 1
|
16天前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
18天前
|
缓存 算法 Java
Java 中线程和纤程Fiber的区别是什么?
【10月更文挑战第14天】
45 0
|
11天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
88 38
|
8天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
2天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####