1. Lambda表达式
先看如下代码:
java">public class LambdaDemo {public static void main(String[] args) {// 匿名内部类方式完成goSwimming(new Swimming() {@Overridepublic void swim() {System.out.println("铁汁 , 我们去游泳吧....");}});// lambda表达式的方式完成goSwimming(() -> System.out.println("铁汁 , 我们去游泳吧...."));}public static void goSwimming(Swimming swimming) {swimming.swim();}}interface Swimming {public abstract void swim();
}
由上述代码可见使用Lambda表达式代码更少,关注点更加明确
-
lambda表达式可以理解为对匿名内部类的一种简化 , 但是本质是有区别的
-
面向对象思想 :
- 强调的是用对象去完成某些功能
-
函数式编程思想 :
- 强调的是结果 , 而不是怎么去做
2. Lambda表达式的使用
-
使用前提
- 必须存在一个接口
- 接口中有且只有一个抽象方法
-
格式 : ( 形式参数 ) -> { 代码块 }
- 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
- ->:由英文中画线和大于符号组成,固定写法。代表指向动作
- 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
Lambda 表达式的基本语法是:
java">(parameters) -> expression
- parameters:输入参数,类似于方法的参数列表,可以有多个参数,且参数类型可以省略,由编译器推断。
- ->:箭头操作符,用于分隔输入参数和表达式体。
- expression:Lambda 表达式的实现逻辑,可以是一个简单的表达式或一个代码块。
简化匿名内部类
在没有 Lambda 表达式之前,我们通常使用匿名内部类来实现接口。例如,实现一个没有返回值的 Runnable
接口。
传统的匿名内部类方式:
java">Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("Running...");}
};
new Thread(runnable).start();
Lambda 表达式方式:
java">Runnable runnable = () -> System.out.println("Running...");
new Thread(runnable).start();
Lambda 表达式的形式
1. 无参数
java">() -> System.out.println("Hello, World!");
这是一个不接受任何参数且没有返回值的 Lambda 表达式,执行时打印出 "Hello, World!"。
2. 一个参数
java">x -> x * x;
这是一个接受一个参数 x
,并返回其平方的 Lambda 表达式。
3. 多个参数
java">(x, y) -> x + y;
4. 多个语句
如果 Lambda 表达式包含多个语句,则需要使用大括号 {}
来包含语句,并且可以使用 return
关键字来返回结果。
java">(x, y) -> {int sum = x + y;return sum;
}
3. 函数式接口
在 Java 中,Lambda 表达式依赖于函数式接口(Functional Interface)来传递行为。
3.1 什么是函数式接口:
- 只有一个抽象方法需要重写的接口,函数式接口。函数式接口是允许有其他的非抽象方法的存在例如静态方法,默认方法,私有方法。
- 为了标识接口是一个函数式接口,可以在接口之上加上一个注解: @FunctionalInterface 以示区别
- 在JDK中 java.util.function 包中的所有接口都是函数式接口
3.2 定义函数式接口
要定义一个函数式接口,你只需要保证接口中有一个抽象方法。你可以使用 @FunctionalInterface
注解来显式标明这是一个函数式接口,虽然这个注解是可选的,但它可以帮助编译器检测是否符合函数式接口的规范。
java">@FunctionalInterface
interface MyFunction {void apply(); // 只包含一个抽象方法
}
函数式接口的常见应用
Lambda 表达式通常用于函数式接口中。Java 8 提供了许多内置的函数式接口,如:
Runnable
:用于表示没有输入参数且没有返回值的任务。Consumer<T>
:表示接受一个参数并进行处理,没有返回值。Supplier<T>
:表示没有参数,返回一个值。Function<T, R>
:接受一个参数,返回一个结果。Predicate<T>
:接受一个参数,返回一个布尔值结果。UnaryOperator<T>
:接受一个参数,返回一个与参数类型相同的结果。BinaryOperator<T>
:接受两个相同类型的参数,返回一个与参数类型相同的结果。
3.3 自定义函数式接口
以下是一个简单的函数式接口例子:
java">@FunctionalInterface
interface Greeting {void sayHello(String name);
}public class LambdaExample {public static void main(String[] args) {// 使用 Lambda 表达式实现接口Greeting greet = (name) -> System.out.println("Hello, " + name);greet.sayHello("John"); // 输出:Hello, John}
}
3.4 Java 内置的函数式接口
Consumer
接口
java">import java.util.function.Consumer;public class ConsumerExample {public static void main(String[] args) {// Consumer 接口,接受一个参数并处理Consumer<String> print = (message) -> System.out.println(message);print.accept("Hello, World!"); // 输出:Hello, World!}
}
Function
接口
java">import java.util.function.Function;public class FunctionExample {public static void main(String[] args) {// Function 接口,接受一个参数并返回一个结果Function<Integer, Integer> square = (x) -> x * x;System.out.println(square.apply(5)); // 输出:25}
}
Predicate
接口
java">import java.util.function.Predicate;public class PredicateExample {public static void main(String[] args) {// Predicate 接口,接受一个参数并返回一个布尔值Predicate<Integer> isEven = (x) -> x % 2 == 0;System.out.println(isEven.test(4)); // 输出:trueSystem.out.println(isEven.test(5)); // 输出:false}
}
Supplier
接口
java">import java.util.function.Supplier;public class SupplierExample {public static void main(String[] args) {// Supplier 接口,返回一个结果Supplier<Double> randomValue = () -> Math.random();System.out.println(randomValue.get()); // 输出:一个随机数}
}
3.5 函数式接口的优点
- 简洁性:Lambda 表达式允许你使用简单的方式实现函数式接口的抽象方法,避免了冗长的匿名类写法。
- 更高效的代码复用:你可以在方法或函数中直接传递行为,而不需要为每个行为编写一个实现类。
- 支持函数式编程:Java 引入 Lambda 表达式后,使得 Java 更加支持函数式编程,能够更加灵活地处理数据和逻辑。
函数式接口的常见应用场景
- 事件处理:可以使用函数式接口来表示事件处理器或回调函数。
- 流处理(Stream API):许多操作(如
map
,filter
,reduce
)都依赖于函数式接口。 - 并行计算:可以在并行流处理中使用函数式接口来实现并发任务。
- 回调机制:可以使用函数式接口将回调函数作为参数传递给方法。