Java Lambda 表达式详解

简介

Lambda 表达式是 Java 8 引入的一种简洁的语法,主要用于 简化匿名内部类 的写法,特别适用于 函数式接口(Functional Interface)。

Lambda 表达式的语法

Lambda 表达式的基本格式如下:

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

完整格式

java 复制代码
(参数1, 参数2, ...) -> { 方法体 }

简化规则

  • 参数类型可省略(Java 编译器可自动推断)

  • 只有一个参数时,可以省略括号 (param) -> ... 可写成 param -> ...

  • 只有一条语句时,可以省略 {}return

使用示例

传统匿名内部类

创建一个接口的匿名实现类 并实例化:

java 复制代码
List<String> list = Arrays.asList("A", "B", "C");
list.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

等价于:

java 复制代码
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Running...");
    }
}

Runnable task = new MyRunnable();
task.run();

使用 Lambda

java 复制代码
list.forEach(s -> System.out.println(s));

或者:

list.forEach(System.out::println);

Lambda 适用的接口

Lambda 适用于 函数式接口,即只包含一个抽象方法的接口。常见的有:

函数式接口 方法签名 作用
Runnable void run() 无参数,无返回值
Callable T call() 无参数,有返回值
Comparator int compare(T o1, T o2) 比较两个对象
Consumer void accept(T t) 只消费数据,无返回值
Supplier T get() 只提供数据,有返回值
Function<T, R> R apply(T t) 输入 T,输出 R
Predicate boolean test(T t) 断言(返回布尔值)

详细示例

Runnable(无参数、无返回值)

  • 传统写法
java 复制代码
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello Lambda!");
    }
};
new Thread(r1).start();
  • Lambda
java 复制代码
Runnable r2 = () -> System.out.println("Hello Lambda!");
new Thread(r2).start();
  • 简化写法
java 复制代码
new Thread(() -> System.out.println("Hello Lambda!")).start();

Comparator(多个参数,有返回值)

  • 传统写法
java 复制代码
Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2 - o1;
    }
};
  • Lambda
java 复制代码
Comparator<Integer> comparator = (o1, o2) -> o2 - o1;

Consumer(消费型接口)

  • 传统写法
java 复制代码
Consumer<String> consumer = new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
};
consumer.accept("Hello World!");
  • Lambda
java 复制代码
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("Hello World!");

Function<T, R>(转换型接口)

传统写法

java 复制代码
Function<String, Integer> function = new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
        return s.length();
    }
};
System.out.println(function.apply("Lambda"));
  • Lambda
java 复制代码
Function<String, Integer> function = s -> s.length();
System.out.println(function.apply("Lambda"));

Predicate(断言型接口)

  • 传统写法
java 复制代码
Predicate<Integer> predicate = new Predicate<Integer>() {
    @Override
    public boolean test(Integer num) {
        return num > 10;
    }
};
System.out.println(predicate.test(15)); // true
  • Lambda
java 复制代码
Predicate<Integer> predicate = num -> num > 10;
System.out.println(predicate.test(15)); // true

方法引用

Lambda 表达式还可以用 方法引用(::)来替代更简洁的写法。

类型 示例 等效 Lambda 表达式
静态方法 Integer::parseInt s -> Integer.parseInt(s)
实例方法 String::toUpperCase s -> s.toUpperCase()
对象实例方法 System.out::println s -> System.out.println(s)
构造方法 ArrayList::new () -> new ArrayList<>()

示例:

java 复制代码
List<String> list = Arrays.asList("a", "b", "c");
list.forEach(System.out::println);

Stream API 与 Lambda

Lambda 常配合 Stream API 处理集合:

java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> filteredNames = names.stream()
    .filter(name -> name.length() > 3)
    .map(String::toUpperCase)
    .collect(Collectors.toList());
System.out.println(filteredNames); // [ALICE, CHARLIE]

自定义函数式接口

使用 @FunctionalInterface 自定义一个函数式接口:

java 复制代码
@FunctionalInterface
public interface MyFunction {
    int apply(int a, int b);
}

使用 Lambda

java 复制代码
MyFunction add = (a, b) -> a + b;
System.out.println(add.apply(3, 5)); // 8
  • @FunctionalInterface 不是必须的,但加上后,编译器会强制检查该接口是否符合 函数式接口 规范(即只能有一个抽象方法)。

  • 可以添加 默认方法 和 静态方法,但不能有多个抽象方法:

java 复制代码
@FunctionalInterface
public interface MyFunction {
    int apply(int a, int b);

    default void printHello() {
        System.out.println("Hello");
    }
    
    static void staticMethod() {
        System.out.println("Static Method");
    }
}

方法引用(Method Reference)示例

方法引用是一种特殊的 Lambda 表达式写法,主要用来 简化代码。它可以看作 Lambda 表达式的简写形式,前提是 Lambda 只是调用一个已有的方法。

静态方法引用

java 复制代码
Function<String, Integer> parseInt = Integer::parseInt;
System.out.println(parseInt.apply("123")); // 123

等同于

java 复制代码
Function<String, Integer> parseInt = s -> Integer.parseInt(s);

实例方法引用

对特定对象调用实例方法

java 复制代码
String str = "hello";
Supplier<String> toUpper = str::toUpperCase;
System.out.println(toUpper.get()); // "HELLO"

等同于

java 复制代码
Supplier<String> toUpper = () -> str.toUpperCase();

对象实例方法引用

应用在 map() 这样的场景

java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperNames = names.stream()
    .map(String::toUpperCase)  // 等同于 name -> name.toUpperCase()
    .collect(Collectors.toList());

System.out.println(upperNames); // [ALICE, BOB, CHARLIE]

构造方法引用

如果 Lambda 表达式的目标是创建对象,可以使用 构造方法引用:

java 复制代码
Supplier<ArrayList<String>> listSupplier = ArrayList::new;
ArrayList<String> list = listSupplier.get(); // 创建 ArrayList 实例

等价于

java 复制代码
Supplier<ArrayList<String>> listSupplier = () -> new ArrayList<>();

应用场景:

java 复制代码
Function<Integer, int[]> arrayCreator = int[]::new;
int[] arr = arrayCreator.apply(5); // 创建长度为5的数组
System.out.println(Arrays.toString(arr)); // [0, 0, 0, 0, 0]

方法引用作为方法参数

java 复制代码
public class Demo {
    public static void printSomething(Supplier<String> supplier) {
        System.out.println(supplier.get());
    }

    public static void main(String[] args) {
        printSomething(() -> "Hello World");
        printSomething("Hello"::toUpperCase); // 方法引用
    }
}

.map(String::toUpperCase) 传入 Function?

.map(String::toUpperCase) 中,String::toUpperCase 是符合 Function<T, R> 类型的,而不是 Supplier

  • .map() 方法的参数是 Function<T, R>
java 复制代码
public interface Function<T, R> {
    R apply(T t);
}

// 它接收一个参数 T,返回 R。
  • String::toUpperCase 等价于:
java 复制代码
(String s) -> s.toUpperCase()

"Hello"::toUpperCase 适用于 Supplier

因为 "Hello" 是一个已经存在的 String 对象,不需要参数。

java 复制代码
Supplier<String> supplier = "Hello"::toUpperCase;
System.out.println(supplier.get()); // 输出:HELLO

等价于:

java 复制代码
Supplier<String> supplier = () -> "Hello".toUpperCase();

String::toUpperCase 与 "Hello"::toUpperCase

形式 绑定情况 适用函数式接口 是否需要参数 示例
String::toUpperCase 未绑定(Unbound) Function<String, String> 需要 String 参数 s -> s.toUpperCase()
"Hello"::toUpperCase 已绑定(Bound) Supplier 不需要参数 () -> "Hello".toUpperCase()

Callable 的使用示例

Callable<T>Java 并发包中的一个接口,类似 Runnable,但它可以有返回值,并且可以抛出异常。

示例:使用 ExecutorService.submit() 提交 Callable<T>

java 复制代码
import java.util.concurrent.*;

public class CallableExample {
    public static void main(String[] args) throws Exception {
        // 1. 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 2. 提交 Callable 任务
        Callable<Integer> task = () -> {
            Thread.sleep(2000);
            return 42;
        };

        Future<Integer> future = executor.submit(task);

        // 3. 执行其他任务
        System.out.println("正在执行其他任务...");

        // 4. 获取返回结果
        Integer result = future.get(); // 阻塞等待返回值
        System.out.println("任务结果:" + result); // 输出:42

        // 5. 关闭线程池
        executor.shutdown();
    }
}
  • Callable<Integer> 任务 延迟 2 秒,然后返回 42

  • submit(task) 返回 Future<Integer>,表示异步计算的结果。

  • future.get() 会阻塞,直到 Callable 执行完成并返回结果。

相关推荐
我命由我1234514 分钟前
Kotlin 数据容器 - List(List 概述、创建 List、List 核心特性、List 元素访问、List 遍历)
java·开发语言·jvm·windows·java-ee·kotlin·list
武子康2 小时前
Java-80 深入浅出 RPC Dubbo 动态服务降级:从雪崩防护到配置中心秒级生效
java·分布式·后端·spring·微服务·rpc·dubbo
YuTaoShao5 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw5 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
超浪的晨5 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
双力臂4046 小时前
Spring Boot 单元测试进阶:JUnit5 + Mock测试与切片测试实战及覆盖率报告生成
java·spring boot·后端·单元测试
Edingbrugh.南空6 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring
QQ_4376643147 小时前
C++11 右值引用 Lambda 表达式
java·开发语言·c++
永卿0017 小时前
设计模式-迭代器模式
java·设计模式·迭代器模式
誰能久伴不乏7 小时前
Linux如何执行系统调用及高效执行系统调用:深入浅出的解析
java·服务器·前端