函数式接口 Lambda 表达式好搭档:Predicate、Function、Consumer、Supplier

函数式接口 Lambda 表达式好搭档:Predicate、Function、Consumer、Supplier

    • [一、Lambda 表达式是什么?](#一、Lambda 表达式是什么?)
      • [Lambda 的语法](#Lambda 的语法)
    • [二、函数式接口 ------ Lambda 的好搭档](#二、函数式接口 —— Lambda 的好搭档)
    • 三、四大核心函数式接口详解
      • [1. Predicate<T> ------ 判断真假(过滤)](#1. Predicate<T> —— 判断真假(过滤))
      • [2. Function<T,R> ------ 转换(映射)](#2. Function<T,R> —— 转换(映射))
      • [3. Consumer<T> ------ 消费(处理)](#3. Consumer<T> —— 消费(处理))
      • [4. Supplier<T> ------ 供应(生产)](#4. Supplier<T> —— 供应(生产))
    • 四、它们之间的"化学反应"
    • 五、总结

一、Lambda 表达式是什么?

Lambda 表达式可以理解为一段可以传递的代码块 ,它的本质是一个匿名函数 (没有名字的函数)。在 Java 8 之前,如果你想传递一段行为(比如点击按钮后的操作、集合遍历的逻辑),通常得写一个冗长的匿名内部类,代码看起来很臃肿。Lambda 的出现就是为了简化这种写法。

举个最简单的例子:创建一个线程。

java 复制代码
// 旧写法:匿名内部类
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("线程运行中");
    }
}).start();

// Lambda 写法
new Thread(() -> System.out.println("线程运行中")).start();

是不是瞬间清爽了很多?Lambda 让我们只关注"做什么",而不用写一堆样板代码。

Lambda 的语法

java 复制代码
(参数列表) -> { 方法体 }

常见形式:

  • 无参数() -> System.out.println("Hello")

  • 一个参数 :可以省略括号 x -> x * 2(但建议保留,更清晰)

  • 多个参数(x, y) -> x + y

  • 多条语句 :需要大括号和 return

    java 复制代码
    (x, y) -> {
        int sum = x + y;
        System.out.println(sum);
        return sum;
    }

二、函数式接口 ------ Lambda 的好搭档

Lambda 不能单独使用,它必须赋值给一个函数式接口

什么是函数式接口?就是只有一个抽象方法 的接口(可以有默认方法或静态方法)。Java 中用 @FunctionalInterface 注解来标记(非必须,但推荐)。

常见的函数式接口有:RunnableComparatorActionListener 等。Java 8 为了方便我们使用 Lambda,在 java.util.function 包下新增了几十个函数式接口,其中最常用的就是 Predicate、Function、Consumer、Supplier。下面我们逐一认识它们。


三、四大核心函数式接口详解

1. Predicate ------ 判断真假(过滤)

  • 抽象方法boolean test(T t)
  • 作用 :接收一个参数,返回一个 boolean 值,常用于条件判断或过滤。

生活比喻 :就像一个安检员,检查一个人是否符合条件(比如年龄≥18),符合就放行(true),否则拒绝(false)。

代码示例

java 复制代码
import java.util.function.Predicate;

public class PredicateDemo {
    public static void main(String[] args) {
        // 判断字符串是否为空
        Predicate<String> isEmpty = s -> s == null || s.length() == 0;
        System.out.println(isEmpty.test(""));      // true
        System.out.println(isEmpty.test("hello")); // false

        // 与 Stream 结合:过滤出长度 > 3 的字符串
        List<String> list = Arrays.asList("Java", "Python", "C", "JavaScript");
        list.stream()
            .filter(s -> s.length() > 3)  // filter 接受 Predicate
            .forEach(System.out::println); // 输出: Java Python JavaScript
    }
}

2. Function<T,R> ------ 转换(映射)

  • 抽象方法R apply(T t)
  • 作用 :接收一个 T 类型的参数,返回一个 R 类型的结果,常用于类型转换或提取信息。

生活比喻:就像翻译官,把中文(T)翻译成英文(R)。

代码示例

java 复制代码
import java.util.function.Function;

public class FunctionDemo {
    public static void main(String[] args) {
        // 将字符串转换为它的长度
        Function<String, Integer> strToLength = s -> s.length();
        System.out.println(strToLength.apply("Java")); // 4

        // 与 Stream 结合:将每个字符串转为大写
        List<String> list = Arrays.asList("java", "python", "c++");
        list.stream()
            .map(s -> s.toUpperCase())  // map 接受 Function
            .forEach(System.out::println); // JAVA PYTHON C++
    }
}

3. Consumer ------ 消费(处理)

  • 抽象方法void accept(T t)
  • 作用 :接收一个参数,执行某些操作,没有返回值。常用于遍历集合、打印、存储等。

生活比喻:就像吃货,把食物(T)吃掉,但不产生新东西。

代码示例

java 复制代码
import java.util.function.Consumer;

public class ConsumerDemo {
    public static void main(String[] args) {
        // 打印字符串
        Consumer<String> print = s -> System.out.println(s);
        print.accept("Hello Lambda"); // Hello Lambda

        // 遍历集合并打印
        List<String> list = Arrays.asList("A", "B", "C");
        list.forEach(print); // forEach 接受 Consumer
    }
}

4. Supplier ------ 供应(生产)

  • 抽象方法T get()
  • 作用 :不接受参数,返回一个 T 类型的值。常用于工厂模式、延迟生成或提供默认值。

生活比喻:就像自动售货机,你不需要给它东西,它直接给你一瓶饮料(T)。

代码示例

java 复制代码
import java.util.function.Supplier;

public class SupplierDemo {
    public static void main(String[] args) {
        // 生成一个随机整数
        Supplier<Integer> random = () -> (int)(Math.random() * 100);
        System.out.println(random.get()); // 每次运行结果不同

        // 创建新对象
        Supplier<Student> studentFactory = () -> new Student("张三", 18);
        Student stu = studentFactory.get(); // 调用 get 获得新对象
    }
}

class Student {
    String name;
    int age;
    // 构造方法...
}

四、它们之间的"化学反应"

这四个接口常常配合 Stream API 使用,产生强大的效果:

接口 常用 Stream 方法 作用
Predicate filter() 过滤元素
Function map() 转换元素
Consumer forEach() 遍历处理
Supplier generate() 生成无限流

例如,我们可以组合它们完成一个完整的操作:从一组数字中过滤出偶数,然后将每个偶数平方,最后打印结果。

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
numbers.stream()
       .filter(n -> n % 2 == 0)           // Predicate
       .map(n -> n * n)                    // Function
       .forEach(System.out::println);       // Consumer
// 输出:4 16 36

五、总结

接口 抽象方法 用途 常用场景
Predicate<T> boolean test(T) 条件判断,返回布尔值 过滤、匹配
Function<T,R> R apply(T) 转换,输入T输出R 提取属性、类型转换
Consumer<T> void accept(T) 消费,无返回值 遍历、打印、存储
Supplier<T> T get() 生产,提供对象 工厂、懒加载、生成随机值

相关推荐
遨游xyz1 小时前
Trie树(字典树)
开发语言·python·mysql
Java后端的Ai之路1 小时前
【JDK】-JDK 17 新特性整理(比较全)
java·开发语言·后端·jdk17
郝学胜-神的一滴1 小时前
Effective Modern C++ 条款40:深入理解 Atomic 与 Volatile 的多线程语义
开发语言·c++·学习·算法·设计模式·架构
小小小米粒2 小时前
Spring Boot Starter ,不止是 “打包好配置的工具类包”
java·开发语言
一个天蝎座 白勺 程序猿2 小时前
国产数据库破局之路——KingbaseES与MongoDB替换实战:从场景到案例的深度解析
开发语言·数据库·mongodb·性能优化·kingbasees·金仓数据库
沛沛rh452 小时前
Rust 中的三个“写手“:print!、format!、write! 的详细区别
开发语言·后端·rust
tod1132 小时前
C++核心知识点全解析(四)
开发语言·c++·面试经验
用户8307196840822 小时前
告别冗余!Spring Boot Web 入参转换 6 种玩法,@InitBinder 可以退休了
java·spring boot
Desirediscipline2 小时前
#include<limits>#include <string>#include <sstream>#include <iomanip>
java·开发语言·前端·javascript·算法