易君召
发布于 2026-08-19 / 作者:易君召 / 4 阅读
0

Lambda 表达式与函数式接口结合使用

核心规则Lambda 本质就是函数式接口的一个实例,Lambda 用来实现函数式接口里唯一的抽象方法,省去写匿名内部类的样板代码。

1. 什么是函数式接口

函数式接口:有且仅有一个抽象方法的接口,可以用注解 @FunctionalInterface 标记(注解是校验用,不是必须)。

@FunctionalInterface
public interface Calculator {
    // 唯一抽象方法
    int calc(int a, int b);
}

注意:可以包含 default 默认方法、static 静态方法、Object 的方法,不影响函数式接口判定,只限制抽象方法只能 1 个

Java 内置大量函数式接口,在java.util.function包:

接口

抽象方法

用途

Predicate<T>

boolean test(T t)

判断条件,返回布尔

Consumer<T>

void accept(T t)

消费数据,无返回

Supplier<T>

T get()

生产数据,无入参

Function<T,R>

R apply(T t)

转换,T 入参,R 返回

2. Lambda 语法格式

(参数列表) -> {方法体}
  • 参数列表:对应接口抽象方法入参,可以省略类型;

  • -> Lambda 运算符;

  • 方法体:实现抽象方法逻辑;单行可以省略{}return

对比:匿名内部类 vs Lambda

// 1.传统匿名内部类
Calculator c1 = new Calculator() {
    @Override
    public int calc(int a, int b) {
        return a + b;
    }
};

// 2.Lambda写法,直接实现接口唯一抽象方法
Calculator c2 = (a,b) -> a + b;

//调用
System.out.println(c2.calc(3,5)); //8

👉 Lambda 直接赋值给函数式接口类型变量,编译器根据接口推断参数、返回值类型,叫类型推断

3. 几种 Lambda 简写形式

@FunctionalInterface
interface NoParam{ void run(); }

@FunctionalInterface
interface OneParam{ void say(String msg); }

public class Demo {
    public static void main(String[] args) {
        // 无参数,多行方法体
        NoParam np = ()->{
            System.out.println("无参");
        };

        // 单个参数,可以省略括号
        OneParam op = msg -> System.out.println(msg);

        //多行语句,必须大括号,return不能省略
        Calculator cal = (x,y)->{
            int res = x * y;
            return res;
        };
    }
}

4. 把 Lambda 作为方法参数(最常用场景)

方法形参定义为函数式接口类型,调用时直接传入 Lambda 表达式。

示例 1:自定义接口作为参数

@FunctionalInterface
interface Filter {
    boolean test(String s);
}

public class Test {
    // 参数是函数式接口Filter
    public static void print(String[] arr, Filter filter){
        for (String s : arr) {
            if(filter.test(s)){
                System.out.println(s);
            }
        }
    }

    public static void main(String[] args) {
        String[] arr = {"java","python","go"};
        //传入Lambda,实现Filter的test方法
        print(arr, s->s.length()>3);
    }
}

示例 2:JDK 内置接口,Stream 流大量使用

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        // Predicate是函数式接口,lambda实现test
        list.stream().filter(x->x>2).forEach(System.out::println);
    }
}
  • filter(Predicate p):接收 Predicate 函数式接口,lambda 实现判断逻辑

  • forEach(Consumer c):接收 Consumer,lambda 实现消费逻辑

5. 方法引用(Lambda 的进一步简写)

当 Lambda 只是调用一个已有方法,可以替换为方法引用 ::,仍然绑定函数式接口。

List<String> list = Arrays.asList("a","b");
//lambda
list.forEach(s-> System.out.println(s));
//方法引用简写
list.forEach(System.out::println);

6. 常见坑点

  1. Lambda 只能捕获 final 或者 effectively final 变量:lambda 内部不能修改外部局部变量;

int num = 10;
// num = 20; //如果修改,下面lambda报错,要求effectively final
Runnable r = ()-> System.out.println(num);
  1. 接口必须仅有一个抽象方法,否则编译器不知道 Lambda 实现哪个抽象方法,编译报错;

  2. Lambda 不是对象,没有继承关系,只是函数式接口的实现实例。

7. 完整小结

  1. Lambda不能单独存在,必须依附函数式接口;

  2. @FunctionalInterface标记接口,强制校验只有一个抽象方法;

  3. Lambda 可以赋值给函数式接口变量,也可以传给接收函数式接口的方法;

  4. 编译器根据目标函数式接口,推断 Lambda 的参数、返回值类型;

  5. Stream API 大量使用内置函数式接口 + Lambda,是日常开发最主要场景。


本文原创作者:易君召,详见:https://www.yijunzhao.cn/authors/yijunzhao,转载请注明出处。

原文链接 https://www.yijunzhao.cn/archives/lambda-expressions-functional-interfaces-guide

欢迎访问 小易撩挨踢

https://www.yijunzhao.cn/