Java函数接口和Lambda表达式深入分析

 更新时间:2025年04月05日 11:45:32   作者:忆愿  
这篇文章主要介绍了Java函数接口和Lambda表达式,函数接口是一个具有单个抽象方法的接口,接口设计主要是为了支持Lambda表达式和方法引用,使得Java能更方便地实现函数式编程风格,需要的朋友可以参考下

一、函数接口

函数接口是一个具有单个抽象方法的接口,接口设计主要是为了支持 Lambda 表达式和方法引用,使得 Java 能更方便地实现函数式编程风格。

特点和用途:

  • 单一抽象方法: 函数接口只能有一个抽象方法,但可以有多个默认方法(default)或静态方法(static)。
  • Lambda 表达式: 可以使用函数接口创建 Lambda 表达式,从而简洁地表示匿名函数,例如在集合操作、线程处理等场景中。
  • 方法引用: 可以通过函数接口的类型来引用一个已存在的方法,使代码更简洁和可读性更高。

Java 8 提供了几个标准的函数接口,接口通常位于 java.util.function 包中。

常见的函数接口:

Consumer: 接收一个输入参数并且不返回结果的操作。

Consumer<String> printConsumer = str -> System.out.println(str);
printConsumer.accept("Hello World!");

Supplier: 不接收参数但是返回结果的提供型接口。

Supplier<Double> randomSupplier = () -> Math.random();
System.out.println(randomSupplier.get());

Function: 接收一个输入参数,并返回结果。

Function<Integer, String> intToString = num -> String.valueOf(num);
System.out.println(intToString.apply(123));

Predicate: 接收一个输入参数,并返回一个布尔值结果。

Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(5)); // false

UnaryOperator: 继承自 Function<T, T>,表示一元操作符。

UnaryOperator<Integer> square = num -> num * num;
System.out.println(square.apply(5)); // 25

自定义函数接口:只需确保接口中只有一个抽象方法即可。

@FunctionalInterface
interface MyFunctionalInterface {
    void myMethod();
    // 允许有默认方法和静态方法
    default void anotherMethod() {
        System.out.println("Default method");
    }
}
// 使用自定义的函数接口
MyFunctionalInterface myFunc = () -> System.out.println("Hello Custom Functional Interface");
myFunc.myMethod();
myFunc.anotherMethod();

二、Lambda表达式简介

Lambda 表达式可以被视为匿名函数的一种声明方式,允许将函数作为方法参数传递,或者在需要函数式接口的地方使用。

基本结构:

// parameters:参数列表,可以为空或非空
// ->:箭头符号,分隔参数列表和Lambda表达式的主体
// expression:单行表达式作为 Lambda 主体
(parameters) -> expression

// { statements; }:代码块作为 Lambda 主体,可以包含多条语句和返回语句
(parameters) -> { statements; }

表达式的特点:

  • 简洁性和可读性: Lambda 表达式使代码更为简洁,尤其是在处理函数式接口时,省去了冗余的语法。
  • 函数式编程风格: Lambda 表达式支持函数式编程,可以轻松地进行函数传递、方法引用和流式操作等。
  • 闭包性: Lambda 表达式可以捕获其周围的变量,使得函数式编程中的状态管理更加灵活。

案例:通过 Lambda 表达式为 MathOperation 接口的 operation 方法提供了四种不同的实现:加法、减法、乘法和除法。

接口的定义:

interface MathOperation {
    int operation(int a, int b);
}

使用 Lambda 表达式来实现这个接口,以便传递不同的数学运算逻辑:

public class LambdaDemo {
    public static void main(String[] args) {
        // Lambda 表达式实现加法
        MathOperation addition = (int a, int b) -> a + b;
        System.out.println("10 + 5 = " + operate(10, 5, addition));
        // Lambda 表达式实现减法
        MathOperation subtraction = (a, b) -> a - b;
        System.out.println("10 - 5 = " + operate(10, 5, subtraction));
        // Lambda 表达式实现乘法
        MathOperation multiplication = (int a, int b) -> { return a * b; };
        System.out.println("10 * 5 = " + operate(10, 5, multiplication));
        // Lambda 表达式实现除法
        MathOperation division = (a, b) -> a / b;
        System.out.println("10 / 5 = " + operate(10, 5, division));
    }
    private static int operate(int a, int b, MathOperation mathOperation) {
        return mathOperation.operation(a, b);
    }
}

三、Lambda表达式外部参数

Lambda 表达式有自己特定的作用域规则,可以捕获和访问其周围的变量, 可以随意引用外部变量,但如果外部变量是在当前作用域声明的,则一定不可以进行第二次赋值,哪怕是在 lambda 语句之后。

局部变量:Lambda 表达式可以访问它们所在方法的局部变量,但是这些变量必须是隐式最终或实际上是最终的(final)。这意味着变量一旦赋值后不再改变。Lambda 表达式内部不允许修改这些局部变量的值,否则编译器会报错。

public class LambdaScopeDemo {
    public static void main(String[] args) {
        int num = 10; // 局部变量
        MathOperation addition = (int a, int b) -> {
            // num = 5; // 错误!Lambda 表达式不能修改局部变量的值
            // 这里访问了局部变量 num
            return a + b + num;
        };
        System.out.println(addition.operation(5, 3));
    }
}

字段:Lambda 表达式可以访问外部类的字段(成员变量),包括实例字段和静态字段。

public class LambdaScopeDemo {
    private static int staticNum; // 静态字段
    private int instanceNum; // 实例字段
    public void testLambdaScope() {
        MathOperation addition = (int a, int b) -> {
            // 访问实例字段和静态字段
            int result = a + b + instanceNum + staticNum;
            return result;
        };
        System.out.println(addition.operation(5, 3));
    }
}

接口的默认方法:Lambda 表达式可以访问接口中定义的默认方法,但不能访问接口中定义的实例字段。

四、Lambda范例

使用Lambda表达式时,常见的场景包括对集合的遍历、排序、过滤以及与函数式接口的结合使用。

常见的Java 8 Lambda表达式示例:

遍历集合

public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        // 使用 Lambda 表达式遍历集合
        names.forEach(name -> System.out.println(name));
    }

使用函数式接口进行计算

参考:二、Lambda表达式简介

使用函数式接口进行条件过滤

public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        // 使用 Lambda 表达式过滤偶数
        System.out.println("偶数:");
        filter(numbers, n -> n % 2 == 0);
        // 使用 Lambda 表达式过滤大于 5 的数
        System.out.println("大于 5 的数:");
        filter(numbers, n -> n > 5);
    }
    private static void filter(List<Integer> numbers, Predicate<Integer> condition) {
        for (Integer number : numbers) {
            if (condition.test(number)) {
                System.out.print(number + " ");
            }
        }
        System.out.println();
    }

使用Comparator进行集合排序

public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        // 使用 Lambda 表达式进行排序(根据字符串长度)
        names.sort((s1, s2) -> s1.length() - s2.length());
        // 输出排序后的结果
        names.forEach(name -> System.out.println(name));
    }

使用 Runnable 执行代码块

参考:五、Runnable Lambda表达式

五、Runnable Lambda表达式

使用 Lambda 表达式来简洁地实现 Runnable 接口的实例化。Runnable 接口是一个函数接口,它只包含一个抽象方法 void run(),用于定义一个可以由线程执行的任务。

匿名内部类(Java 7 及之前):

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("Running in a separate thread");
    }
};
Thread thread = new Thread(runnable);
thread.start();

Lambda 表达式(Java 8+):

Runnable runnable = () -> {
    System.out.println("Running in a separate thread");
};
Thread thread = new Thread(runnable);
thread.start();

更简洁的方式:任务非常简单,可以进一步简化,直接将 Lambda 表达式作为参数传递给 Thread 的构造函数:

Thread thread = new Thread(() -> {
    System.out.println("Running in a separate thread");
});
thread.start();

这种方式避免了显式地声明 Runnable 变量,使代码更加紧凑和易读。

案例:

public static void main(String[] args) {
        // 使用 Lambda 表达式创建一个新的线程
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("线程执行:" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        // 启动线程
        thread.start();
    }

以上就是Java函数接口和Lambda表达式深入分析的详细内容,更多关于Java函数接口的资料请关注脚本之家其它相关文章!

相关文章

  • Spring中管理bean对象的方式(专业级说明)

    Spring中管理bean对象的方式(专业级说明)

    在Spring框架中,Bean的管理是核心功能,主要通过IoC(控制反转)容器实现,下面给大家介绍Spring中管理bean对象的方式,感兴趣的朋友一起看看吧
    2025-06-06
  • 探讨java深拷贝

    探讨java深拷贝

    这篇文章主要针对java深拷贝的相关内容进行解析,帮助大家学习理解java深拷贝,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • 通过代码实例解析JAVA类生命周期

    通过代码实例解析JAVA类生命周期

    这篇文章主要介绍了通过代码实例解析JAVA类生命周期,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • MyBatis分页的四种方式

    MyBatis分页的四种方式

    分页查询是非常常见的需求,本文主要介绍了MyBatis分页的四种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-08-08
  • java Socket实现简单模拟HTTP服务器

    java Socket实现简单模拟HTTP服务器

    这篇文章主要介绍了java Socket实现简单模拟HTTP服务器,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • POI通用导出Excel(.xls,.xlsx)的方法

    POI通用导出Excel(.xls,.xlsx)的方法

    这篇文章主要介绍了POI通用导出Excel(.xls,.xlsx)的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • Java使用POI实现excel文件的导入和导出

    Java使用POI实现excel文件的导入和导出

    这篇文章主要为大家详细介绍了Java如何使用POI实现excel文件的导入和导出功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • java实现ThreadLocal线程局部变量的实现

    java实现ThreadLocal线程局部变量的实现

    本文主要介绍了java实现ThreadLocal线程局部变量的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • 解决使用json-lib包实现xml转json时空值被转为空中括号的问题

    解决使用json-lib包实现xml转json时空值被转为空中括号的问题

    网上能查到的xml转json的jar包大部分是net.sf.json-lib,但是JSON json =xmlSerializer.read(xml); 方法会出现将空值转化为[]的问题,下面为大家提供两种解决方法
    2018-03-03
  • Spring中@Cacheable注解的使用详解

    Spring中@Cacheable注解的使用详解

    这篇文章主要介绍了Spring中@Cacheable注解的使用详解,Spring框架提供了@Cacheable注解来轻松地将方法结果缓存起来,以便在后续调用中快速访问,本文将详细介绍@Cacheable注解的使用方法,并从源码级别解析其实现原理,需要的朋友可以参考下
    2023-11-11

最新评论