Java
Python前端运维数据库
Java
Java
  • 新特性
    • Record
    • Optional
  • 面向对象
    • 面向对象基础
    • 构造方法
    • 继承与多态
    • 接口
    • 修饰符
    • 代码块
    • 接口(Interface)
    • 枚举类
  • IO流
    • IO
      • 字节流
      • 字符流
      • 缓冲流
      • 转换流
      • 操作ZIP
      • File 对象
    • NIO
      • Channel和Buffer
      • 异步文件通道AsynchronousFileChannel
      • Selector
      • Path/Files/Pipe
  • 反射
  • 内存分配
  • 集合
    • 简介
    • List
    • Set
    • Map
    • EnumMap
  • 日期与时间
    • Date和Calendar
    • Java8 新时间 ✨
      • LocalDateTime
      • ZonedDateTime
      • Duration
    • 时间格式化
      • SimpleDateFromat
      • DateTimeFormatter ✨
    • Instant
    • 实践
  • 网络编程
    • IP 地址
    • 网络模型
    • TCP 编程
    • UDP 编程
    • HTTP 编程
  • 加密和安全
  • 并发编程
    • 多线程
    • 线程与进程的区别
    • 线程组和线程优先级
    • 线程池
    • 线程锁
  • 异步任务
    • Future
    • CompletableFuture
      • 开启异步任务
      • 串行任务方法
      • 并行任务方法
      • 任务结束方法
      • 异常处理方法
      • 查看状态方法
      • 设置任务结果方法
  • 执行系统命令
  • Stream 流
    • Stream 流的创建
    • Stream 流串行与并行
    • Stream 流中间操作
    • Stream 流终端操作
  • Lambda 表达式
    • Lambda 表达式简介
    • Lambda 表达式语法
    • 方法引用
  • String
  • StringBuffer
由 GitBook 提供支持
在本页
  • 基本语法
  • 变量的作用域
  • 方法重载
  • 方法引用
  • 类型检查
  • 类型转换
  • 错误处理

这有帮助吗?

  1. Lambda 表达式

Lambda 表达式语法

基本语法

Lambda 表达式的组成:

  1. 参数列表:即方法的参数列表,对应于 Runnable 接口的 run 方法,该方法没有参数,所以这里为空。

  2. 箭头符号:箭头符号将参数列表与 Lambda 表达式的主体分隔开。

  3. Lambda 表达式的主体:即方法体,对应于 Runnable 接口的 run 方法的方法体。

new Thread(() -> System.out.println("Hello World")).start();

Lambda 表达式可以分为以下几种形式:

// 01、无参数,无返回值
() -> System.out.println("Hello World")

// 02、有一个参数,无返回值
(String name) -> System.out.println("Hello " + name)

// 03、有一个参数,无返回值,参数类型可以省略
name -> System.out.println("Hello " + name)

// 04、有多个参数,无返回值
(String name, int age) -> System.out.println("Hello " + name + ", age is " + age)

// 05、有多个参数,无返回值,参数类型可以省略
(name, age) -> System.out.println("Hello " + name + ", age is " + age)

// 06、有返回值
() -> {
    System.out.println("Hello World");
    return "Hello World";
}

// 07、有返回值,单条语句,return 与大括号可以省略
() -> "Hello World"

// 08、有返回值,单条语句,return 与大括号可以省略,参数类型可以省略
name -> "Hello " + name

// 09、有返回值,多条语句,return 与大括号不能省略
() -> {
    System.out.println("Hello World");
    return "Hello World";
}

变量的作用域

Lambda 表达式中可以访问外部的变量,但是有以下限制:

  1. Lambda 表达式中访问的外部变量必须是 final 或者 effectively final 的。

  2. Lambda 表达式中访问的外部变量不能被修改,即不能对外部变量进行赋值操作。

class Sample {
    public static void main(String[] args) {
        String value = "World";
        Person person = (message) -> {
            System.out.println(message + " " + value);
            // ❌ value = "Java";
        };
        
        // 重新赋值,输出那里编译器会报错
        value = "Java";
        person.say("Hello");
    }
}

方法重载

使用 Lambda 表达式时,调用一个类中的重载方法,且方法中的参数都为函数式接口时,编译器会报错。因为编译器无法推断 Lambda 表达式的类型。

@FunctionalInterface
interface MyInterfaceA {
    void myMethod(String name);
}
@FunctionalInterface
interface MyInterfaceB {
    void myMethod(String name);
}

class Sample {
    public static void method(MyInterfaceA myInterfaceA) {
        myInterfaceA.myMethod("Hello");
    }

    public static void method(MyInterfaceB myInterfaceb) {
        myInterfaceb.myMethod("Hello");
    }

    public static void main(String[] args) {
        // ⭕️ ❌编译报错,无法推断 Lambda 表达式的类型
        method(str -> System.out.println(str + " World!"));
        
        // ✅ 解决方法是显式指定 Lambda 表达式的类型。
        method((MyInterfaceA) str -> System.out.println(str + " World!"));
        method((MyInterfaceB) str -> System.out.println(str + " World!"));
    }
}

方法引用

Lambda 表达式的方法引用是一种更简洁的 Lambda 表达式的写法,可以直接引用已有方法或者构造方法。

方法引用的语法是 类名::方法名,其中 :: 是方法引用运算符,左边是类名或者对象名,右边是方法名。

方法引用的类型:

  1. 静态方法引用:类名::静态方法

  2. 实例方法引用:对象名::实例方法

  3. 构造方法引用:类名::new

public class LambdaMethodReference {
    public static void main(String[] args) {
        // 01、静态方法引用
        Consumer<String> consumer1 = LambdaMethodReference::print;
        consumer1.accept("Hello World");

        // 02、实例方法引用
        LambdaMethodReference lambdaMethodReference = new LambdaMethodReference();
        Consumer<String> consumer2 = lambdaMethodReference::println;
        consumer2.accept("Hello World");

        // 03、构造方法引用
        Supplier<LambdaMethodReference> supplier = LambdaMethodReference::new;
        LambdaMethodReference lambdaMethodReference1 = supplier.get();
    }
}
// 定义一个接受三个参数的函数式接口 TriFunction
@FunctionalInterface
interface TriFunction<T, U, V, R> {
    R apply(T t, U u, V v);
}

class Sample {
    public static void main(String[] args) {
        List<Student> students = List.of(
                new Student("张三", 10, "男"),
                new Student("李四", 20, "男"),
                new Student("王五", 30, "女")
        );

        // 静态方法引用
        List<Student> filterPersons = Sample.filter(students, Sample::adult);

        // 实例方法引用
        List<Student> filter = Sample.filter(students, new Sample()::isAdult);

        // 使用带参构造方法引用创建 Student 对象
        TriFunction<String, Integer, String, Student> studentFactory = Student::new;

        List<String> names = List.of("张三", "李四", "王五");
        List<Integer> ages = List.of(20, 21, 22);
        List<String> genders = List.of("男", "男", "女");
        List<Student> studs = names.stream()
                .map(name -> {
                    int index = names.indexOf(name);
                    return studentFactory.apply(name, ages.get(index), genders.get(index));
                })
                .toList();

    }

    static List<Student> filter(List<Student> students, Filter filter) {
        List<Student> result = new ArrayList<>();
        for (Student student : students) {
            if (filter.call(student)) {
                result.add(student);
            }
        }
        return result;
    }

    static Boolean adult(Student student) {
        return student.getAge() >= 18;
    }

    static void print(Student student) {
        System.out.println(student);
    }

    public Boolean isAdult(Student student) {
        return student.getAge() >= 18;
    }
}

如果函数的参数超过2个,就需要自己创建一个函数式接口。

类型检查

Lambda 表达式的类型检查是通过上下文推断来实现的,Lambda 表达式的类型是通过上下文推断出来的,而不是通过 Lambda 表达式的参数类型来推断的。

// 01、通过上下文推断出 Lambda 表达式的类型是 Runnable
Runnable runnable = () -> System.out.println("Hello World");

// 02、通过上下文推断出 Lambda 表达式的类型是 Callable
Callable<String> callable = () -> "Hello World";

类型转换

Lambda 表达式的类型转换是通过强制类型转换来实现的,Lambda 表达式的类型是通过上下文推断出来的,而不是通过 Lambda 表达式的参数类型来推断的。

// 01、通过上下文推断出 Lambda 表达式的类型是 Runnable
Runnable runnable = () -> System.out.println("Hello World");

// 02、通过强制类型转换将 Lambda 表达式转换为 Callable 类型
Callable<String> callable = (Callable<String>) () -> "Hello World";

错误处理

Lambda 表达式中的代码可能会抛出异常,但是 Lambda 表达式中不能使用 throws 关键字来声明异常,因为函数式接口中的抽象方法没有声明异常。

public class LambdaException {
    public static void main(String[] args) {
        // Lambda 表达式中不能使用 throws 关键字
        // Callable<String> callable = () -> { throw new Exception(); };
    }
}

Lambda 表达式中的异常处理有以下几种方式:

  1. 使用 try-catch 语句捕获异常。

  2. 使用 Callable 函数式接口,将 Lambda 表达式的返回值改为 Callable 类型,然后在 call 方法中捕获异常。

  3. 使用自定义函数式接口,将 Lambda 表达式的抽象方法声明异常。

public class LambdaException {
    public static void main(String[] args) {
        // 01、使用 try-catch 语句捕获异常
        Callable<String> callable1 = () -> {
            try {
                throw new Exception();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "Hello World";
        };

        // 02、使用 Callable 函数式接口捕获异常
        Callable<String> callable2 = new Callable<String>() {
            @Override
            public String call() {
                try {
                    throw new Exception();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return "Hello World";
            }
        };

        // 03、使用自定义函数式接口捕获异常
        MyCallable myCallable = () -> {
            throw new Exception();
        };
    }
}
上一页Lambda 表达式简介下一页方法引用

最后更新于8个月前

这有帮助吗?