JDK新特性
Lambda表达式
什么是Lambda表达式
Lambda表达式是一个匿名代码块,用于简单的传递一段代码片段。
Lambda表达式标准格式
格式:(形式参数) -> {代码块}
- 形式参数
如果有多个参数,参数只见用逗号隔开;如果没有,留空即可- ->
由英文中画线和大于符号组成,固定写法。代表指向动作。- 代码块
是我们具体要做的事情,也就是我们以前写的方法体内容
// 组成Lambda表达式的三要素:形式参数,箭头,代码块
// 示例
new Thread(() -> System.out.println("这是一个示例")).start();
Lambda表达式的使用前提
- 有一个接口
- 接口中有且仅有一个抽象方法
理解Lambda表达式
定义一只接口(Eatable),里面定义一个抽象方法:void eat();表示吃这一个动作。
然后以实现类,匿名内部类,Lambda表达式分别实现一下小明吃饭了这一动作。
通用接口 Eatable.java
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();
}
}
执行结果
Lambda表达式实现
测试代码
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();
}
}
执行结果
对比实现类,匿名内部类,Lambda表达式编译文件
通过实现类方式实现,会生成EatImpl.class文件
通过匿名内部类方式实现,会生成LambdaDemo01$1.class匿名内部类文件
通过Lambda方式实现,不会额外生成文件,实现字节码会动态生成
Lambda表达式的省略模式
省略规则:
- 参数类型可以省略,但是多个参数的情况下,不能只省略一个
- 如果参数有且仅有一个,那么小括号可以省略
- 如果代码块的语句只有一条,大括号和分号可以省略,甚至是return
测试代码
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("小明");
}
}
执行结果
Lamda表达式的方法引用
学习lamda千万不要注意方法,一定要关心方法的入参的个数和类型以及出参的类型,不要关注方法的名称
方法引用被分为了好几类:
- 静态方法引用 Class::methodName
- 实例方法引用 objInstance::methodName
- 引用类中的非静态方法:Class::methodName
- 引用类的构造方法:Class::new 其中Class就是类名,后面跟“::new”,这个是固定写法哈,即使为了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));
}
}
执行结果
Lambda表达式优缺点
Java 8中引入了lambda表达式,使得代码编写更加简洁、优雅。lambda表达式是一个匿名函数,可以作为参数传递给方法或者存储在变量中。在Java中使用lambda表达式可以有以下优点和缺点:
优点
- 代码简洁:使用lambda表达式可以减少冗余的代码量,使得代码更加简洁明了。特别是在编写只有一个抽象方法的接口时,可以将其替换为lambda表达式。
- 促进函数式编程:lambda表达式使得函数式编程成为可能。函数式编程强调函数的纯粹性和不可变性,有助于减少副作用和提高代码的可维护性。通过lambda表达式,我们可以将函数作为一等公民,并在不改变状态的情况下进行操作。
- 更好的代码复用:使用lambda表达式可以更方便地实现代码的复用。可以将一段逻辑封装在一个lambda表达式中,然后在多个地方使用。
- 并行处理能力:在Java 8之前,要实现多线程或并行处理需要编写大量的代码。使用lambda表达式可以方便地编写并行处理的代码,充分利用多核处理器的性能。
- 提升代码可读性:lambda表达式将逻辑封装在一个更加紧凑的形式中,使得代码更易读。通过命名良好的lambda表达式,可以使代码的意图更加清晰。
缺点
- 学习成本:lambda表达式是一个新的概念,在Java中引入了新的语法。对于初学者来说,学习和理解lambda表达式需要一些时间和努力。
- 可读性差:虽然lambda表达式可以提升代码的可读性,但是过于复杂的lambda表达式可能反而降低代码的可读性。尤其是当lambda表达式包含多个参数、多行代码或复杂的逻辑时,可读性会受到影响。
- 调试困难:由于lambda表达式是匿名函数,调试时可能会更加困难。在调试过程中,无法直接跟踪lambda表达式的执行路径,可能会增加调试的难度。
- 性能问题:lambda表达式的性能可能比传统的方法调用略差。虽然这个差距很小,但是在某些高性能场景下可能会有所影响。
总结:
lambda表达式是Java 8引入的一项强大的功能,对于简化代码、促进函数式编程、提升代码可读性和代码复用等方面都有很大的帮助。
然而,它也存在着一些学习成本高、可读性差、调试困难和性能问题等缺点。
在使用lambda表达式时,需要根据具体情况权衡利弊,选择合适的使用方式。
gitee源码
git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git