一、函数接口
函数接口是一个具有单个抽象方法的接口,接口设计主要是为了支持 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 方法提供了四种不同的实现:加法、减法、乘法和除法。
三、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 表达式可以访问接口中定义的默认方法,但不能访问接口中定义的实例字段。
四、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
变量,使代码更加紧凑和易读。
0条评论
点击登录参与评论