Comparator接口、Lambda表达式和PriorityQueue优先队列

本文深入探讨了Comparator接口的使用,包括其实现方法、匿名对象代码实例、Lambda表达式的应用及其实现排序的具体方式。同时,文章对比了匿名内部类与Lambda表达式的优劣,详细解析了Lambda表达式在实现Comparator接口时的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Comparator接口

  1. 接口重写方法

Comaparator接口用于实现排序,通常作为排序的参数输入,如Collections.sort(array,Comparator),接口中包含compare(Object obj1,Object obj2)和equals(Object obj)方法,compare方法用于比较obj1和obj2,obj1>obj2,return 大于0的数,相等return0,小于则return小于零的数

  1. 接口的实现方法

接口实现方法:类实现(重写compare方法,equals方法Object类中实现,因此不需要重写)、lambda表达式

  1. 匿名对象代码实例
public void test5() {
        //TreeMap的定制排序
        Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Person1 && o2 instanceof Person1) {
                    Person1 p1 = (Person1) o1;
                    Person1 p2 = (Person1) o2;
                    int i = p1.getSex().compareTo(p2.getSex());
                    if (i == 0) {
                        return p1.getAge().compareTo(p2.getAge());
                    }
                    return i;
                }
                return 0;
            }
        };


        Map map = new TreeMap(com);
        map.put(new Person1("AA", 23), 55);
        map.put(new Person1("CC", 44), 55);
        map.put(new Person1("ZZ", 255), 55);
        map.put(new Person1("DD", 32), 55);
        map.put(new Person1("GG", 11), 55);
        map.put(new Person1("MM", 15), 55);
        map.put(new Person1("CC", 33), 55);
        for (Object a : map.keySet()) {
            System.out.println(a + "=" + map.get(a));
        }

    }

Lambda表达式

Lambda表达式允许通过表达式来代替功能接口功能(注意表达式中参数以及参数方法的一致性,使用中尽量添加泛型约束)
通过另一篇博客进行学习,本文中进行了一些转载和自己的相关测试:Lambda表达式的使用

  1. Lambda表达式的基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }
// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s) 
  1. for循环和Lambda表达式的循环
String[] arr=new String[]{"sdf","dsf","34"};
        List<String> list= Arrays.asList(arr);
        //1、以往for循环
        for(String a:list){
            System.out.print(a+" ");
        }
        System.out.println();
        //2、forEach和Lambda
        //forEach()即增强for循环方法,测试发现引用数据类型Integer和String等没有这个方法
        list.forEach((a)-> System.out.print(a+" "));

在这里插入图片描述

  1. 匿名内部类和Lambda
    注意:Lambda用于实现匿名内部类方法时,内部类继承的接口应只有一个抽象方法,否则虚拟机不能判断调用哪个方法,报错
//1、匿名内部类
        Person p1=new Person(){
            @Override
            public void run() {
                System.out.println("hello");
            }
        };
        //2、Lambda
        Person p2=()-> System.out.println("hello");

        p1.run();
        p2.run();

在这里插入图片描述

  1. Lambda作为功能接口实现排序
    Lambda作为排序参口传递进方法中,也就是说Lambda可以替代Comparator接口作为排序参数
    三种排序接口的实现方式(使用TreeMap作为参考):
    (1)匿名类对象实现Comparator接口
 Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Person1 && o2 instanceof Person1) {
                    Person1 p1 = (Person1) o1;
                    Person1 p2 = (Person1) o2;
                    int i = p1.getSex().compareTo(p2.getSex());
                    if (i == 0) {
                        return p1.getAge().compareTo(p2.getAge());
                    }
                    return i;
                }
                return 0;
            }
        };
        Map map = new TreeMap(com);

(2)Lambda表达式实现Comparator接口

Comparator<Person1> com1=(p1,p2)->p1.getAge().compareTo(p2.getAge());
Map map=new TreeMap(com1);

**注意:**在网上找了一些学习资料后,自己测试过程中遇到了Comparator com1=(p1,p2)->p1.getAge().compareTo(p2.getAge());这行代码报错的问题,刚开始以为是Person1类中我没有实现compareTo方法,但是修改后还是不对,多次测试后发现,Comparator中,T默认为Object类,因此只要输入参数p1和p2不是此类就会报错,而且Lambda表达式中会自动识别输入参数类,不需要用类来修饰。
(3)匿名Lambda表达式
TreeMap构造器中传入匿名Lambda表达式时需要加泛型,在使用匿名Lambda方法时需要注意

 Map map=new TreeMap<>((Person1 p1,Person1 p2)->p1.getAge().compareTo(p2.getAge()));

PriorityQueue优先队列

  1. PeiorityQueue之前没有总结过,这里做个总结,底层使用小顶堆二叉树实现,因此能够实现由小到大的排序,底层数组的第0个索引元素为最小值
  2. 小顶堆的排序方法可以通过传入排序接口对象实现,这里采用匿名Lambda方法
  3. 实例化方法
//源码:
public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator);
    }
//测试:
 PriorityQueue heap=new PriorityQueue<Integer>((n1,n2)->n1-n2);
  1. add()、offer()方法
//add()、offer():向优先队列中添加元素,插入失败add()抛出异常,offer()返回false
heap.offer(20);
heap.offer(1);
heap.offer(58);
System.out.println(heap);

在这里插入图片描述
可以看到,每添加一个元素,优先队列就按照排序方法排序为小顶堆

  1. element()、peek()
//element()、peek():都是获取但不删除队首元素,方法失败时前者抛出异常,后者返回null
        System.out.println(heap.peek());

在这里插入图片描述

  1. remove()、poll()
 PriorityQueue heap=new PriorityQueue<Integer>((n1,n2)->n1-n2);
        heap.offer(20);
        heap.offer(15);
        heap.offer(58);
        heap.offer(17);
        System.out.println(heap);
        //remove()、poll():获取并删除队首元素,当方法失败时前者抛出异常,后者返回null
        //按照小顶堆二叉树原理,将根节点元素和最后一个叶节点元素调换,并删去此叶节点,之后对二叉树重新小顶堆
        heap.poll();
        System.out.println(heap);

在这里插入图片描述
在这里插入图片描述

### Java 中自定义优先队列的排序规则 在 Java 中,`PriorityQueue` 是一种基于堆结构的数据容器,其内部元素按照指定的优先级自动排列。默认情况下,`PriorityQueue` 使用对象的自然顺序来决定优先级。如果需要自定义排序规则,则可以通过提供 `Comparator` 来覆盖默认行为。 以下是具体实现方式: #### 创建带有自定义比较器的优先队列 通过向 `PriorityQueue` 的构造函数传递一个实现了 `Comparator<T>` 接口的对象,可以定义自己的排序逻辑。下面是一个完整的代码示例,展示如何创建并使用具有自定义排序规则的优先队列。 ```java import java.util.PriorityQueue; import java.util.Comparator; public class CustomPriorityQueueExample { public static void main(String[] args) { // 定义一个自定义比较器,按字符串长度降序排列 Comparator<String> customComparator = new Comparator<String>() { @Override public int compare(String s1, String s2) { return Integer.compare(s2.length(), s1.length()); // 长度越大的越靠前 } }; // 初始化带自定义比较器的优先队列 PriorityQueue<String> priorityQueue = new PriorityQueue<>(customComparator); // 添加一些测试数据到队列中 priorityQueue.add("apple"); priorityQueue.add("banana"); priorityQueue.add("kiwi"); priorityQueue.add("watermelon"); // 输出队首元素(最高优先级) System.out.println("Highest Priority Element: " + priorityQueue.peek()); // 移除并打印所有元素 while (!priorityQueue.isEmpty()) { System.out.println(priorityQueue.poll()); } } } ``` 上述代码中的核心部分在于 `Comparator` 的实现[^1]。这里我们重写了 `compare` 方法,使得字符串按照它们的长度从大到小排序。当调用 `poll()` 或者 `peek()` 时,返回的是当前队列中满足该条件的最大值。 #### Lambda 表达式的简化写法 自从 Java 8 开始支持 lambda 表达式以来,编写简单的匿名类变得更为简洁明了。对于上面的例子,我们可以改用如下更紧凑的形式表达相同的逻辑: ```java // 使用Lambda表达式替代传统匿名内部类 PriorityQueue<String> priorityQueue = new PriorityQueue<>((s1, s2) -> Integer.compare(s2.length(), s1.length())); ``` 这种形式不仅减少了冗余代码量,还提高了可读性开发效率[^2]。 #### 注意事项 - 如果传入的比较器违反了一致性原则(即不遵循全序关系),则可能导致不可预测的行为。 - 当尝试存储 null 值或者无法相互比较的对象实例进入此类集合时会抛出异常。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值