赞
踩
Lambda表达式是一个匿名代码块,用于简单的传递一段代码片段。
格式:(形式参数) -> {代码块}
- 形式参数
如果有多个参数,参数只见用逗号隔开;如果没有,留空即可- ->
由英文中画线和大于符号组成,固定写法。代表指向动作。- 代码块
是我们具体要做的事情,也就是我们以前写的方法体内容
// 组成Lambda表达式的三要素:形式参数,箭头,代码块
// 示例
new Thread(() -> System.out.println("这是一个示例")).start();
定义一只接口(Eatable),里面定义一个抽象方法:void eat();表示吃这一个动作。
然后以实现类,匿名内部类,Lambda表达式分别实现一下小明吃饭了这一动作。
package demo01; /** * 定义吃接口 * * @author Anna. * @date 2024/3/31 22:35 */ public interface Eatable { /** * 吃 * * @param * @return void * @author Anna. * @date 2024/3/31 22:35 */ void eat(); }
创建一个实现类(EatImpl)实现(Eatable)接口
package demo01;
/**
* 吃实现类
*
* @author Anna.
* @date 2024/3/31 22:37
*/
public class EatImpl implements Eatable{
@Override
public void eat() {
System.out.println("通过实现类-小明吃东西了");
}
}
测试代码
package demo01; import java.util.Arrays; /** * Demo01: * 定义一只接口(Eatable),里面定义一个抽象方法:void eat();表示吃这一个动作。 * 然后以实现类,匿名内部类,Lambda表达式分别实现一下小明吃饭了这一动作。 * * @author Anna. * @date 2024/3/31 22:36 */ public class LambdaDemo01 { public static void main(String[] args) { // 通过实现类实现 Eatable eat = new EatImpl(); eat.eat(); } }
执行结果
测试代码
package demo01; import java.util.Arrays; /** * Demo01: * 定义一只接口(Eatable),里面定义一个抽象方法:void eat();表示吃这一个动作。 * 然后以实现类,匿名内部类,Lambda表达式分别实现一下小明吃饭了这一动作。 * * @author Anna. * @date 2024/3/31 22:36 */ public class LambdaDemo01 { public static void main(String[] args) { // 匿名内部类方式实现 eat(new Eatable() { @Override public void eat() { System.out.println("通过匿名内部类方式实现-小明吃东西了"); } }); } /** * 定义一个调用Eatable接口eat()的方法 * * @param eatable * @return void * @author Anna. * @date 2024/3/31 22:50 */ private static void eat(Eatable eatable){ eatable.eat(); } }
执行结果
测试代码
package demo01; import java.util.Arrays; /** * Demo01: * 定义一只接口(Eatable),里面定义一个抽象方法:void eat();表示吃这一个动作。 * 然后以实现类,匿名内部类,Lambda表达式分别实现一下小明吃饭了这一动作。 * * @author Anna. * @date 2024/3/31 22:36 */ public class LambdaDemo01 { public static void main(String[] args) { // Lambda表达式实现 eat(() -> { System.out.println("通过Lambda表达式实现-小明吃东西了"); }); } /** * 定义一个调用Eatable接口eat()的方法 * * @param eatable * @return void * @author Anna. * @date 2024/3/31 22:50 */ private static void eat(Eatable eatable) { eatable.eat(); } }
执行结果
通过实现类方式实现,会生成EatImpl.class文件
通过匿名内部类方式实现,会生成LambdaDemo01$1.class匿名内部类文件
通过Lambda方式实现,不会额外生成文件,实现字节码会动态生成
省略规则:
测试代码
package demo02; import demo01.Eatable; /** * Demo02: * Lambda表达式省略模式 * * @author Anna. * @date 2024/3/31 22:36 */ public class LambdaDemo02 { public static void main(String[] args) { // 正常调用 System.out.println("=========正常调用========="); eat(() -> { System.out.println("小明吃东西了"); }); sum((int x, int y) -> { return x + y; }); sleep((String name) -> { System.out.println(name + "睡觉了"); }); // 省略模式 System.out.println("=========省略模式========="); System.out.println("=========参数类型可以省略========="); sleep((name) -> { System.out.println(name + "睡觉了"); }); // 参数类型可以省略,但是多个参数的情况下,不能只省略一个 System.out.println("=========参数类型可以省略,但是多个参数的情况下,不能只省略一个========="); sum((x, y) -> { return x + y; }); // 如果参数有且仅有一个,那么小括号可以省略 System.out.println("=========如果参数有且仅有一个,那么小括号可以省略========="); sleep(name -> { System.out.println(name + "睡觉了"); }); // 如果代码块的语句只有一条,大括号和分号可以省略 System.out.println("=========如果代码块的语句只有一条,大括号和分号可以省略========="); sleep(name -> System.out.println(name + "睡觉了")); // 如果代码块的语句只有一条,且有返回值 return 也可以省略 System.out.println("=========如果代码块的语句只有一条,且有返回值 return 也可以省略========="); sum((x, y) -> x + y); } /** * 定义一个调用Eatable接口eat()的方法 * * @param eatable * @return void * @author Anna. * @date 2024/3/31 23:11 */ private static void eat(Eatable eatable) { eatable.eat(); } /** * 定义一个调用Sumable接口sum()的方法 * * @param sumable * @return void * @author Anna. * @date 2024/3/31 23:11 */ private static void sum(Sumable sumable) { System.out.println(sumable.sum(20, 30)); } /** * 定义一个调用Sleepable接口sleep()的方法 * * @param sleepable * @return void * @author Anna. * @date 2024/3/31 23:11 */ private static void sleep(Sleepable sleepable) { sleepable.sleep("小明"); } }
执行结果
在Lambda表达式中访问外层作用域和旧版本的匿名对象中的方式类似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
Lambda表达式不会从超类(supertype)中继承任何变量名,也不会引入一个新的作用域。
Lambda表达式基于词法作用域,也就是说lambda表达式函数体里面的变量和它外部环境的变量具有相同的语义(也包括lambda表达式的形式参数)。
此外,this关键字及其引用,在Lambda表达式内部和外部也拥有相同的语义。
可以直接在lambda表达式中访问外层的局部变量<br/>
在Lambda 表达式当中被引用的变量的值不可以被更改。<br/>
案例
public class LambdaDemo5 {
public static void main(String[] args) {
final String count = "123";
int num = 0;
new Thread(() -> {
num = 100; // 编译报错
count = "232"; // 编译报错
}, "Lambda表达式").start();
}
}
编译结果
可以直接在lambda表达式中访问外层的局部变量。
lambda表达式的局部变量(eg:num)可以不用声明为final,不过这里的局部变量(eg:num)必须不可被后面的代码修改(即隐性的具有final的语义)。
案例
public class LambdaDemo501 {
public static void main(String[] args) {
final String count = "123";
int num = 0;
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "num:" + num);
System.out.println(Thread.currentThread().getName() + "count:" + count);
}, "Lambda表达式").start();
}
}
执行结果
Lambda 表达式中使用 this 会引用创建该 Lambda 表达式的方法的 this 参数。
案例
package demo05; import java.util.function.Supplier; /** * Lambda作用域 * * @author Anna. * @date 2024/4/1 11:07 */ public class LambdaDemo05 { public static void main(String[] args) { LambdaDemo05 lambdaDemo05 = new LambdaDemo05(); lambdaDemo05.scopeTest01(); } public void scopeTest01() { System.out.println("方法体中使用this:" + this); pase(() -> { System.out.println("Lambda中使用this:" + this); return null; }); } public static <T> T pase(Supplier<T> supplier) { return supplier.get(); } }
执行结果
::该符号为引用运算符,而它所在的表达式被称为方法引用
通过实现将字符串数字转换为int类型,来体验方法引用
Conversion.java
package demo04;
/**
* 定义一个接口将字符串数字转换成int类型
*
* @author Anna.
* @date 2024/4/1 11:06
*/
public interface Conversion {
int pase(String s);
}
LambdaDemo04.java
package demo04; /** * 方法引用 * * @author Anna. * @date 2024/4/1 11:07 */ public class LambdaDemo04 { public static void main(String[] args) { // 使用Lambda表达式实现 System.out.println("使用Lambda表达式实现"); pase(s -> Integer.parseInt(s)); // 使用方法引用实现 System.out.println("使用方法引用实现"); pase(Integer::parseInt); } public static void pase(Conversion c) { System.out.println(c.pase("123")); } }
执行结果
回顾分析:
Lambda表达式: pase(s -> Integer.parseInt(s));
拿到参数s之后,传递给Integer.parseInt方法处理,返回结果
方法引用:pase(Integer::parseInt);
直接使用Integer::parseInt方法来取代Lambda表达式,代码更加简洁
结论:
如果使用Lambda表达式,那么根据“可推导即可省略”的原则,无需指定参数类,也无需指定的重载形式,他们都将被自动推导
如果使用方法引用,也同样可以根据上下文进行推导
方法引用可以被分为一下几类:
格式: 类名::静态方法
格式: 对象::成员方法
示例: pase(“HelloWorld”::toUpperCase); 等价于 pase(s -> s.toUpperCase());
格式: 类名::成员方法
格式: 类名::new
Sumable.java
package demo3;
public interface Sumable {
int sum(int x, int y);
}
SumImpl.java
package demo3;
public class SumImpl implements Sumable {
@Override
public int sum(int x, int y) {
return x + y;
}
}
SumUtils.java
package demo3;
public class SumUtils {
public int sum(int x, int y) {
return x + y;
}
}
IEntityDo.java
package demo3;
public interface IEntityDo {
SumEntity init(int x, int y);
}
SumEntity.java
package demo3; public class SumEntity { private int x; private int y; public SumEntity(int x, int y) { this.x = x; this.y = y; } @Override public String toString() { return "SumEntity{" + "x=" + x + ", y=" + y + '}'; } }
LambdaDemo03.java
package demo3; /** * Demo03: * Lambda表达式方法引用 * * @author Anna. * @date 2024/3/31 22:36 */ public class LambdaDemo03 { public static void main(String[] args) { System.out.println("Lambda方法"); sum(((x, y) -> x + y)); System.out.println("静态方法引用"); sum(Integer::sum); System.out.println("实例方法引用"); Sumable sumable = new SumImpl(); sum(sumable::sum); System.out.println("如果该接口有且仅有一个抽象方法,还可以进一步省略::内容"); sum(sumable); System.out.println("引用类中的非静态方法"); SumUtils sumUtils = new SumUtils(); sum(sumUtils::sum); System.out.println("引用类的构造方法"); init(SumEntity::new); } /** * 定义一个调用Sumable接口sum()的方法 * * @param sumable * @return void * @author Anna. * @date 2024/3/31 23:11 */ private static void sum(Sumable sumable) { System.out.println(sumable.sum(20, 30)); } /** * 定义一个调用EntityDo接口init()的方法 * * @param entityDo * @return void * @author Anna. * @date 2024/3/31 23:11 */ private static void init(IEntityDo entityDo) { System.out.println(entityDo.init(20, 30)); } }
执行结果
Java 8中引入了lambda表达式,使得代码编写更加简洁、优雅。lambda表达式是一个匿名函数,可以作为参数传递给方法或者存储在变量中。在Java中使用lambda表达式可以有以下优点和缺点:
优点
缺点
总结:
lambda表达式是Java 8引入的一项强大的功能,对于简化代码、促进函数式编程、提升代码可读性和代码复用等方面都有很大的帮助。
然而,它也存在着一些学习成本高、可读性差、调试困难和性能问题等缺点。
在使用lambda表达式时,需要根据具体情况权衡利弊,选择合适的使用方式。
git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。