参考链接:
Lambda表达式本质上是一段匿名内部类,也可称为闭包,我们可以将Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递),使用它可以写出简洁、灵活的代码,作为一种更紧凑的代码风格,使java语言表达能力得到提升。
Lambda表达式在java语言中引入了一种新的语法元素和操作,允许把函数作为一个方法的参数(函数作为参数传递进方法中),Lambda表达式操作符为“->”(也称箭头操作符)。它将Lambda表达式分割为两部分, 左边:指Lambda表达式的所有参数,右边:指Lambda体,即表示Lambda表达式需要执行的功能。即:传入参数->利用参数执行功能。
lambda表达式的重要特征如下:
-
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
-
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
-
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
-
可选的返回关键字:如果主体只有一个表达式返回值,则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
0. Lambda标准格式
Lambda省去了面向对象的条条框框,Lambda的标准格式格式由3个部分组成:
(参数类型 参数名称) -> {
代码体;
}
格式说明:
-
(参数类型 参数名称):参数列表
-
{代码体;}:方法体
-
-> :箭头:分隔参数列表和方法体
0.1 使用前提条件
Lambda的语法非常简洁,但是Lambda表达式不是随便使用的,使用时有几个条件要特别注意:
-
方法的参数或局部变量类型必须为接口才能使用Lambda
-
接口中有且仅有一个抽象方法
举例:
-
设计一个接口,接口中定义一个抽象方法
public interface Flyable {
public abstract void flying();
}
-
测试类
public class TestFlyable {
public static void main(String[] args) {
test01(() -> {
});
Flyable s = new Flyable() {
@Override
public void flying() {
}
};
Flyable s2 = () -> {
};
}
public static void test01(Flyable fly) {
fly.flying();
}
}
0.2 省略形式
在Lambda标准格式的基础上,使用省略写法的规则为:
-
小括号内参数的类型可以省略
-
如果小括号内有且仅有一个参数,则小括号可以省略
-
如果大括号内有且仅有一个语句,可以同时省略大括号、return关键字及语句分号
举例:
(int a) -> {
return new Student();
}
省略后
a -> new Student()
0.3 其它
-
lambda表达式访问局部变量 ,变量的引用可以不用final来修饰 ,但作用与final一样,不能被改变。
-
lambda表达式中不允许内参数与外参数命名相同
0.4 Lambda和匿名内部类对比
-
所需的类型不一样
-
匿名内部类需要的类型可以是类、抽象类、接口
-
Lambda表达式需要的类型必须是接口
-
-
抽象方法的数量不一样
-
匿名内部类所需的接口中抽象方法的数量随意
-
Lambda表达式所需的接口只能有一个抽象方法
-
-
实现原理不同
-
匿名内部类是在编译后会形成class
-
Lambda表达式是在程序运行的时候动态生成class
-
具体使用如下:
1. 无输入参数,无返回值
格式:()->
举例说明:
package lambda;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @ClassName Test01
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/9/18 9:43
* @Version 1.0
*/
public class Test01 {
// 使用log4j需要导入slf4j-log4j12、log4j的jar包,同时编写log4j的配置文件log4j.properties
private static Logger log = LoggerFactory.getLogger(Test01.class);
public static void main(String[] args) {
/**
* Runnable接口是线程辅助类,仅定义了一个方法run()方法
* 并且不接受任何参数,不返回任何值。
*/
// 使用匿名内部类形式创建Runnable实现类
Runnable t1 =new Runnable(){
@Override
public void run(){
log.info("我是没有使用Lambda表达式:不简洁");
}
};
// 使用lambda表达式简化匿名内部类形式创建Runnable实现类
Runnable t2 = () -> log.info("我是使用Lambda表达式:简洁、灵活");
t1.run();
t2.run();
}
}
输出结果:
[main] INFO lambda.Test01 - 我是没有使用Lambda表达式:不简洁 [main] INFO lambda.Test01 - 我是使用Lambda表达式:简洁、灵活
附:
-
log4j依赖
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
log4j.properties
# Configure logging for testing: optionally with log file #log4j.rootLogger=debug,appender log4j.rootLogger=info,appender #log4j.rootLogger=error,appender #\u8F93\u51FA\u5230\u63A7\u5236\u53F0 log4j.appender.appender=org.apache.log4j.ConsoleAppender #\u6837\u5F0F\u4E3ATTCCLayout log4j.appender.appender.layout=org.apache.log4j.TTCCLayout
2. 一个输入参数,无返回值
格式:(a)->
举例说明:
package lambda;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.Consumer;
/**
* @ClassName Demo03
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/9/18 10:12
* @Version 1.0
*/
public class Demo03 {
private static Logger log = LoggerFactory.getLogger(Demo03.class);
public static void main(String[] args) {
// 使用匿名内部类形式创建Consumer实例
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
log.info(s);
}
};
consumer.accept("爱与被爱的区别");
// 使用lambda表达式简化匿名内部类形式创建Consumer实例
Consumer<String> consumer1 = (s)->log.info(s);
consumer1.accept("接受爱不一定爱对方,爱一定付出真心爱");
}
}
输出结果:
[main] INFO lambda.Demo03 - 爱与被爱的区别 [main] INFO lambda.Demo03 - 接受爱不一定爱对方,爱一定付出真心爱
3. 一个输入参数时,输入参数外面()可以省略
格式:a->
// 使用lambda表达式简化匿名内部类形式创建Consumer实例
Consumer<String> consumer2 = s->log.info(s);
consumer2.accept("无论结果怎样,请相信爱,放手去爱");
输出结果:
[main] INFO lambda.Demo03 - 无论结果怎样,请相信爱,放手去爱
4. 两个输入参数,无返回值
格式:(a,b)->
举例说明:
package lambda;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Comparator;
public class Demo05 {
private static Logger log = LoggerFactory.getLogger(Demo05.class);
public static void main(String[] args) {
CompareOldMethod(12,10);
findMaxValue(12,10);
findMinValue(12,10);
}
// 使用匿名内部类形式创建Comparator实例比较大小
public static void CompareOldMethod(int num1,int num2){
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
log.info("o1:{}",o1);
log.info("o2:{}",o2);
return o1 < o2 ? o2 : o1;
}
};
log.info("OldFindMaxValue:{}",comparator.compare(num1,num2));
}
// 使用lambda表达式简化匿名内部类形式创建Comparator实例比较大小
public static void findMaxValue(int num1,int num2){
Comparator<Integer> comparatorMax = (o1, o2) ->{
log.info("o1:{}",o1);
log.info("o2:{}",o2);
return o1 < o2 ? o2 : o1;
};
log.info("findMaxValue:{}",comparatorMax.compare(num1,num2));
}
public static void findMinValue(int num1,int num2){
Comparator<Integer> comparatorMin = (o1,o2)->{
log.info("o1:{}",o1);
log.info("o2:{}",o2);
return o1 < o2 ? o1 : o2;
};
log.info("findMinValue:{}",comparatorMin.compare(num1,num2));
}
}
输出结果:
[main] INFO lambda.Demo05 - o1:12 [main] INFO lambda.Demo05 - o2:10 [main] INFO lambda.Demo05 - OldFindMaxValue:12 [main] INFO lambda.Demo05 - o1:12 [main] INFO lambda.Demo05 - o2:10 [main] INFO lambda.Demo05 - findMaxValue:12 [main] INFO lambda.Demo05 - o1:12 [main] INFO lambda.Demo05 - o2:10 [main] INFO lambda.Demo05 - findMinValue:10
5. lambda体只有一条语句时,return和{}均可省略
举例说明:输出结果同上
package lambda;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Comparator;
public class Demo05 {
private static Logger log = LoggerFactory.getLogger(Demo05.class);
public static void main(String[] args) {
CompareOldMethod(12,10);
findMaxValue(12,10);
findMinValue(12,10);
}
// 使用匿名内部类形式创建Comparator实例比较大小
public static void CompareOldMethod(int num1,int num2){
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
log.info("o1:{}",o1);
log.info("o2:{}",o2);
return o1 < o2 ? o2 : o1;
}
};
log.info("OldFindMaxValue:{}",comparator.compare(num1,num2));
}
// 使用lambda表达式简化匿名内部类形式创建Comparator实例比较大小
public static void findMaxValue(int num1,int num2){
Comparator<Integer> comparatorMax = (o1, o2) -> o1 < o2 ? o2 : o1;
log.info("findMaxValue:{}",comparatorMax.compare(num1,num2));
}
public static void findMinValue(int num1,int num2){
Comparator<Integer> comparatorMin = (o1,o2)->o1 < o2 ? o1 : o2;
log.info("findMinValue:{}",comparatorMin.compare(num1,num2));
}
}
6. 类型判断
举例说明:
package lambda;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.Consumer;
public class Demo07 {
private static Logger log = LoggerFactory.getLogger(Demo07.class);
public static void main(String[] args) {
dateType();
}
public static void dateType(){
// 指明输入参数为String类型
Consumer<String> consumer = (String s) -> log.info(s);
consumer.accept("我是指定了输入类型的");
// 不指明输入参数类型
Consumer<String> consumer1 = (s) -> log.info(s);
consumer1.accept("我没有指定输入类型哦");
}
}
输出结果:
[main] INFO lambda.Demo07 - 我是指定了输入类型的 [main] INFO lambda.Demo07 - 我没有指定输入类型哦
结论:数据类型可以省略,因为编译器可以推断得出,成为“类型推断”。
7. 举例
7.1 创建线程
当需要启动一个线程去完成任务时,通常会通过 Runnable 接口来定义任务内容,并使用 Thread 类来启动该线程。
传统写法:
package com.zhq.test;
public class Lambda01 {
public static void main(String[] args) {
/*
一、使用匿名内部类存在的问题
public Thread(Runnable target)
二、匿名内部类做了哪些事情
1.定义了一个没有名字的类
2.这个类实现了Runnable接口
3.创建了这个类的对象
以上可以看出:
1.使用匿名内部类语法是很冗余的
2.其实我们最关注的是run方法和里面要执行的代码.
*/
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类方式");
}
}).start();
}
}
由于面向对象的语法要求,首先创建一个 Runnable 接口的匿名内部类对象来指定线程要执行的任务内容,再将其 给一个线程来启动。
代码分析:
对于Runnable的匿名内部类用法,可以分析出几点内容:
-
Thead 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心。
-
为了指定 run 的方法体,不得不需要 Runnable 接口的实现类
-
为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类
-
必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错,而实际上,似乎只有方法体才是关键所在。
优化后:
public class Lambda01 {
public static void main(String[] args) {
// Lambda表达式体现的是函数式编程思想,只需要将要执行的代码放到函数中(函数就是类中
new Thread(() -> {
System.out.println("Lambda表达式");
}).start();
}
}
通过了解匿名内部类语法冗余,体验了Lambda表达式的使用,发现Lambda是对匿名内部类的简写。
本文详细介绍了Java 8中的Lambda表达式,包括其基本概念、语法特点、使用场景等,并通过具体示例展示了如何使用Lambda表达式简化代码。
5623

被折叠的 条评论
为什么被折叠?



