Lambda表达式和比较器的学习

前几天在写算法题的时候用到了优先队列这个数据结构, 当时还不太会用比较器和Lambda表达式, 正好趁此机会搞明白这两个东西的设计的来龙去脉和用法.

Lambda表达式正是比较器的一个很好的应用, 因为比较器是一个函数式接口, Lambda表达式就专门是为了简化函数式接口的使用而出现的.

一. Lambda表达式

问题背景

函数式接口:

就是一个类里面只有一个抽象方法, 这种类就叫函数式接口. 因为我们把这个接口的实现类对象当函数来用所以叫做函数式接口.

函数式接口的一般的使用流程:

  1. 创建一个实现类重写实现这个接口的方法
  2. new一个实现类的对象
  3. 将这个对象赋值给这个接口的引用变量, 变成一个引用
  4. 用这个接口引用去调用其唯一的方法---当作函数用

1. 匿名内部类

我们在上面的使用流程中发现有一步可以简化, 这一步就是第一步, 这一步我们要创建实现类, 但是正如我们问题背景所说, 我们单单是想把这个接口当函数用, 所以我们只关心这个函数式接口中的函数方法有没有实现, 是怎么实现的.

像是想实现类的名字这种东西我们完全可以简化掉, 由此产生了匿名内部类这个语法, 这就是我们对于函数式接口使用的第一次简化.

匿名内部类的使用方法:

  1. 我们现在有一个函数式接口, 假设叫做Runnable, Runnable里面有一个抽象方法叫run
  2. 现在我们要创建实现类重写这个抽象方法, 并把实现类对象赋给这个接口的引用变量
  3. 看看匿名内部类的语法是怎么做到的
Java 复制代码
Runnable task = new Runnable() { 
    @Override 
    public void run() { 
        System.out.println("任务执行"); 
    } 
};
  1. 这个语法是新加的, 和以前的语法都不一样, 以前的语法是一个类我们可以在等式右边直接new出来, 并且输入初始化参数, 在创建对象的同时执行初始化方法. 匿名内部类是在右边加了{ }, 重写了一个抽象方法, 然后再new出来这个对象赋给左边接口引用, 这时因为没有给这个实现类命名所以叫做匿名内部类

2. Lambda表达式

Lambda表达式也是用来简化函数式接口的使用的, 函数式接口的使用流程中甚至1和2都可以简化, 因为我们只关心函数式接口的函数方法是怎么实现的. 所以我们借助了编译器的帮助进一步简化了函数式接口的使用.

函数式接口的使用方法:

  1. 同样现在有一个函数式接口, 假设叫做Runnable, Runnable里面有一个抽象方法叫run
  2. 现在我们要创建实现类重写这个抽象方法, 并把实现类对象赋给这个接口的引用变量
  3. 看看Lambda表达式的语法是怎么做到的
Java 复制代码
Runnable task = () -> System.out.println("任务执行");
  1. 首先编译器会判断当前位置引用变量是否为函数式接口的引用变量, 如果是便会用这个Lambda表达式重写他的函数方法, 函数方法原本有什么形参Lambda表达式中的形参类型和数量也要在( )中对应, 名字可以不一样. 然后把->后的作为函数体赋给函数方法, 最后创建这个实现类的对象赋给这个函数式接口的引用变量, 就可以通过这个引用来调用函数方法了.

注意Lambda表达式有一个语法细节:

1.单行表达式(无花括号 {}

自动返回表达式结果, 无需写 return, 返回的就是s1.length() - s2.length()的值

Java 复制代码
Comparator<String> byLength = (s1, s2) -> s1.length() - s2.length();

2.多行代码块(有花括号 {}

必须显式写 return 语句(如果有返回值)

Java 复制代码
Function<int[], Integer> sumOfSquares = arr -> {
    int sum = 0;
    for (int num : arr) {
        sum += num * num;
    }
    return sum;  // 必须显式返回
};

二. 比较器

比较器实际上就是一个函数式接口, 我们要实现比较器里面的函数方法, 所以前面的Lambda表达式是一个很常用的手段.比较器的比较函数进行了如下的约定, 用来判断你放入的两个元素谁排在前面, 谁排在后面.

函数方法输入(o1, o2)两个元素, 比较器的唯一核心规则

  • 返回负数 → 约定排序算法中o1 排在 o2 前面
  • 返回正数 → 约定排序算法中o2 排在 o1 前面
  • 返回0 → 顺序无关紧要

比较器的 compare(o1, o2) 方法本质是一个"裁判 ",它只返回一个整数(负 / 正 / 0),根据规则排序算法再操作:"o1o2 谁应该排在前面"

所以我们现在不管排序算法中的内容, 现在会用比较器的规则就行

  • 升序小的在前 → 应返回o1的属性 - o2的属性, 此时正负都是小的在前
  • 降序大的在前 → 应返回o2的属性 - o1的属性, 此时正负都是大的在前
  • 多条件:依次比较每个条件,直到返回非零结果。

我们先记住这个框架,遇到任何排序需求先能快速推导, 以后看排序算法的源码会有更深的理解.

相关推荐
是一个Bug2 分钟前
Java后端开发面试题清单(50道)
java·开发语言·jvm
GIS 数据栈3 分钟前
【Seggis遥感系统升级】用C++高性能服务Drogon重构软件服务架构|QPS提升300%,性能再升级!
java·开发语言·c++·重构·架构
2301_780669867 分钟前
List(特有方法、遍历方式、ArrayList底层原理、LinkedList底层原理,二者区别)
java·数据结构·后端·list
Coder码匠7 分钟前
策略模式的实际应用:从单一数据源到多数据源架构
java·架构·策略模式
零度@20 分钟前
Java 消息中间件 - ActiveMQ 保姆级全解2026
java·activemq·java-activemq
weixin_3993806923 分钟前
TongWeb异常宕机问题分析
java·tomcat
小鸡脚来咯24 分钟前
设计模式面试介绍指南
java·开发语言·单例模式
怦怦蓝28 分钟前
详解 IntelliJ IDEA 中编写邮件发送功能(从环境搭建到实战落地)
java·spring boot·intellij-idea
DENG86230429 分钟前
二、使用idea运行Quarkus项目及调试
java·intellij-idea·quarkus