在正式开始之前,先用官方话术描述一下什么是Lambda表达式 ~Lambda 表达式是一种匿名函数,也可称为闭包,简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。Lambda 表达式也是Java8中最值得学习的新特性之一。主要作用是:对接口进行非常简洁的实现,从而简化代码。
注意在上述描述中有一个名词:“匿名函数”。那么什么是“匿名函数”呢?在了解这个概念之前我们要知道“什么是匿名内部类?”,这篇文章将一点点将“Lambda 表达式”说清楚、让每一位伙伴都对Java8的这一新特性熟悉、并进行使用~ LET'S GO
一、什么是匿名内部类?
关于内部类一共可以分为四种:“成员内部类”、“局部内部类”、“匿名内部类”、“静态内部类”,其中“匿名内部类”需要重点掌握,这里呢也介绍这一种,另外三种较为简单,了解即可。有兴趣的伙伴可以普及~
匿名内部类:在类中定义一个没有名称只有类体的类,一般使用在抽象类和实现类(接口)中。
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称() {
// 覆盖重写所有抽象方法
};
下面分别从这两种形式去认识匿名内部类,废话不说,直接上代码!!
抽象类:
package com.example.rabbitmq_demo.niebulei;
/**
* @ClaseName: Animal$
* @Description:匿名内部类-抽象
* @Author: wuhs
* @Date: 2023/7/26$ 17:43$
*
*/
public abstract class Animal {
// 抽象方法
public abstract void eat();
public static void main(String[] args) {
//正常调用方式,先创建实现类,然后调用方法
Animal cat = new Cat();
Animal dog = new Dog();
dog.eat();
// 下列方式是使用匿名内部类调用
// Animal animal = new Animal() ;错误的,抽象类不能直接实例化,要加上方法体
Animal a = new Animal() {
//实现里面的抽象方法
@Override
public void eat() {
System.out.println("女朋友,吃吃喝喝逛逛gai");
}
};
a.eat();
}
}
//创建实现类
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
//创建实现类
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
接口实现类:
package com.example.rabbitmq_demo.niebulei;
public interface Car {
//接口中创建两个方法
void run();
void stop();
public static void main(String[] args) {
// 使用匿名内部类实现接口的方法
// 示例:去创建一个五菱宏光,并实现里面的方法
Car wlhgCar = new Car() {
@Override
public void run() {
System.out.println("五菱宏光MINI,跑起来YYDS");
}
@Override
public void stop() {
System.out.println("五菱宏光MINI,立马停了下来");
}
};
wlhgCar.run();
wlhgCar.stop();
}
}
//通常接口中的实现方式,需要创建一个类,然后实现接口,重写接口里面的方法
class BMcar implements Car{
@Override
public void run() {
}
@Override
public void stop() {
}
}
通过上面的两个实例,会对“匿名内部类”有个大概认识。而接下来还需要对一个名词有所了解--“函数式接口”,因为lambda 表达式只能实现函数式接口。那么什么是“函数式接口”?
函数式接口:一个接口中,要求实现类必须实现的抽象方法,有且只有一个!这样的接口,就是函数式接口。具体看代码!
//这个接口中,有且只有一个方法,是实现类必须实现的,因此是一个函数式接口
interface Test1 {
void test();
}
//这个接口中,实现类必须要实现的方法,有两个!因此不是一个函数式接口
interface Test2{
void test1();
void test2();
}
//这个接口中,实现类必须要实现的方法,有零个!因此不是一个函数式接口
interface Test3 {
}
//这个接口中,虽然没有定义任何的方法,但是可以从父接口中继承到一个抽象方法的。是一个函数式接口
interface Test4 extends Test1 {
}
//这个接口,虽然里面定义了两个方法,但是defualt方法子类不是必须实现的。
//因此,实现类实现这个接口的时候,必须实现的方法只有一个!是一个函数式接口。
interface Test5 {
void test5();
default void test(){}
}
//这个接口中的toString方法,是object类中定义的方法。
//此时,实现类在实现接口的时候,toString可以不重写的!因为可以从父类Object中继承到!
//此时,实现类在实现接口的时候,有且只有一个方法是必须要重写的。是一个函数式接口!
interface Test6 {
void test6();
String toString();
}
知道这些之后,下面进入主题---->
二、Lambda表达式的语法
lambda表达式,其实本质来讲,就是一个匿名函数。因此在写lambda表达式的时候,不需要关心方法名是什么。
实际上,我们在写lambda表达式的时候,也不需要关系返回值类型。
我们在写lambda表达式的时候,只需要关注两部分内容即可: 参数列表 和 方法体
lambda 表达式的基础语法:
(参数) -> {
方法体
};
1、参数部分: 方法的参数列表,要求和是实现的接口给中的方法参数部分一致,包括参数的数量和类型。2、方法体部分: 方法的实现部分,若果接口中定义的方法有返回值,则在实现的时候,注意返回值的返回。
3、->: 分隔参数部分和方法体部分
在这里介绍一个注解:@FunctionalInterface,是一个注解,用在接口之前,判断这个接口是否是一个函数式接口。如果是函数式接口,没有任何问题。如果不是函数式接口,则会报错。
三、Lambda表达式的使用(实现函数式接口)
1、无返回值、无参数的函数式接口
/**
* @ClaseName: LambdaTest$
* @Description:
* @Author: wuhs
* @Date: 2023/7/28$ 14:07$
*/
//构建一个函数式接口
@FunctionalInterface
public interface LambdaTest01 {
//有且仅有一个方法、并带有一个参数
void getName();
}
// 通常实现方法
class LambdaTest01Impl implements LambdaTest01{
@Override
public void getName() {
System.out.println("这是接口的通常实现方式");
}
}
//接口的Lambda实现类
class mainTest{
public static void main(String[] args) {
LambdaTest01 lambdaTest01 = ()->{
System.out.println("这是接口的Lambda实现方式");
};
lambdaTest01.getName();
}
}
2、无返回值、有一个参数的函数式接口
/**
* @ClaseName: LambdaTest$
* @Description:
* @Author: wuhs
* @Date: 2023/7/28$ 14:07$
*/
//构建一个函数式接口
@FunctionalInterface
public interface LambdaTest01 {
//有且仅有一个方法、并带有一个参数
void getName(String name);
}
// 通常实现方法
class LambdaTest01Impl implements LambdaTest01{
@Override
public void getName(String name) {
System.out.println("这是接口的通常实现方式"+name);
}
}
//接口的Lambda实现类
class mainTest{
public static void main(String[] args) {
/*写法一:
LambdaTest01 lambdaTest01 = (name)->{
System.out.println("这是接口的Lambda实现方式--》"+name);
};*/
// 写法二:参数的()可以省略
LambdaTest01 lambdaTest01 = name->{
System.out.println("这是接口的Lambda实现方式--》"+name);
};
lambdaTest01.getName("张三");
}
}
3、无返回值、有一个以上参数的函数式接口
/**
* @ClaseName: LambdaTest$
* @Description:
* @Author: wuhs
* @Date: 2023/7/28$ 14:07$
*/
//构建一个函数式接口
@FunctionalInterface
public interface LambdaTest01 {
//有且仅有一个方法、并带有一个参数
void getName(String name,int age);
}
// 通常实现方法
class LambdaTest01Impl implements LambdaTest01{
@Override
public void getName(String name,int age) {
System.out.println("这是接口的通常实现方式");
}
}
//接口的Lambda实现类
class mainTest{
public static void main(String[] args) {
LambdaTest01 lambdaTest01 = (String name,int age)->{
System.out.println("这是接口的Lambda实现方式--》"+name+age);
};
lambdaTest01.getName("张三",11);
}
}
注意:lambda表达式参数的类型可以省略,当参数大于一个的时候,要嘛每个参数都带上参数类型,要嘛就一个都不要加,不然会报错!!
4、有返回值、有一个参数的函数式接口
/**
* @ClaseName: LambdaTest$
* @Description:
* @Author: wuhs
* @Date: 2023/7/28$ 14:07$
*/
//构建一个函数式接口
@FunctionalInterface
public interface LambdaTest01 {
//有且仅有一个方法、并带有一个参数
String getName(String name);
}
// 通常实现方法
class LambdaTest01Impl implements LambdaTest01{
@Override
public String getName(String name) {
System.out.println("这是接口的通常实现方式");
return name;
}
}
//接口的Lambda实现类
class mainTest{
public static void main(String[] args) {
LambdaTest01 lambdaTest01 = name->{
System.out.println("这是接口的Lambda实现方式--》"+name);
return name;
};
String getName = lambdaTest01.getName("张三");
System.out.println(getName);
}
}
前面我们提到Lambda表达式作用就是对接口进行非常简洁的实现,从而简化代码。所以在函数式接口中不建议使用较为复杂的代码逻辑,如果有复杂的逻辑要处理,可以将其进行剥离,在Lambda表达式中进行调用,如以下代码所示~
/**
* @ClaseName: LambdaTest$
* @Description:
* @Author: wuhs
* @Date: 2023/7/28$ 14:07$
*/
//构建一个函数式接口
@FunctionalInterface
public interface LambdaTest01 {
//有且仅有一个方法、并带有一个参数
String getName(String name);
}
// 通常实现方法
class LambdaTest01Impl implements LambdaTest01 {
@Override
public String getName(String name) {
System.out.println("这是接口的通常实现方式");
return name;
}
}
//创建一个方法代替一段复杂的代码逻辑
class Cult {
int a1 = 13;
int a2 = 31;
@Override
public String toString() {
return "Cult{" +
"a1=" + a1 +
", a2=" + a2 +
'}';
}
}
//接口的Lambda实现类
class mainTest {
public static void main(String[] args) {
LambdaTest01 lambdaTest01 = name -> {
//其他复杂的逻辑
Cult cult = new Cult();
System.out.println(cult.toString());
System.out.println("这是接口的Lambda实现方式--》" + name);
return name;
};
String getName = lambdaTest01.getName("张三");
System.out.println(getName);
}
}
四、Lambda表达式的使用(静态方法的引用)
语法:
- 类::静态方法
注意事项:
- 在引用的方法后面,不要添加小括号
- 引用的这个方法,参数(数量、类型)和返回值,必须要跟接口中定义的一致
具体操作看下面实例~~~
/**
* @ClaseName: LambdaTest$
* @Description:
* @Author: wuhs
* @Date: 2023/7/28$ 14:07$
*/
//构建一个函数式接口
@FunctionalInterface
public interface LambdaTest01 {
//有且仅有一个方法、并带有一个参数
String getName(String name);
}
class person {
public static String getn(String name) {
return name;
}
}
//接口的Lambda实现类
class mainTest {
public static void main(String[] args) {
/**
LambdaTest01的接口方法getName的实现,调用的person类的getn()方法
需要注意的是:
1、在引用的方法后面,不要添加小括号
2、引用的这个方法,参数(数量、类型)和返回值,必须要跟接口中定义的一致
*/
LambdaTest01 getn = person::getn;
String xgsm = getn.getName("暇光曙墨");
System.out.println(xgsm);
}
}
五、Lambda表达式的使用(非静态方法的引用)
非静态方法的引用和静态方法的引用大同小异,语法如下:
- 对象::非静态方法
需要的注意的事项仍与引用静态方法一致,具体操作看一下代码实例~
/**
* @ClaseName: LambdaTest$
* @Description:
* @Author: wuhs
* @Date: 2023/7/28$ 14:07$
*/
//构建一个函数式接口
@FunctionalInterface
public interface LambdaTest01 {
//有且仅有一个方法、并带有一个参数
String getName(String name);
}
class PerClass {
public String getn(String name) {
return name;
}
}
//接口的Lambda实现类
class mainTest {
public static void main(String[] args) {
/**
LambdaTest01的接口方法getName的实现,调用的person类的getn()方法
需要注意的是:
1、在引用的方法后面,不要添加小括号
2、引用的这个方法,参数(数量、类型)和返回值,必须要跟接口中定义的一致
*/
LambdaTest01 getn = new PerClass()::getn;
System.out.println(getn.getName("暇光曙墨"));
}
}
六、Lambda表达式的使用(构造方法的引用)
使用场景
如果某一个函数式接口中定义的方法,仅仅是为了得到一个类的对象。此时我们就可以使用构造方法的引用,简化这个方法的实现。
语法:
类名::new
注意事项:
可以通过接口中的方法的参数,区分引用不同的构造方法
具体使用方式看如下示例~~
/**
* @ClaseName: LambdaTest$
* @Description:
* @Author: wuhs
* @Date: 2023/7/28$ 14:07$
*/
//构建一个函数式接口
@FunctionalInterface
public interface LambdaTest01 {
//有且仅有一个方法、并带有一个参数
PerClass getName(String name);
}
class PerClass {
int age;
String name;
//无参构造方法
public PerClass() {
System.out.println("这是无参构造方法");
}
//全参构造方法
public PerClass(int age, String name) {
this.age = age;
this.name = name;
System.out.println("这是全参构造方法");
}
// 只有一个参数的构造方法
public PerClass(int age) {
this.age = age;
System.out.println("这是只有一个参数的构造方法,参数是年龄:" + age);
}
//只有一个参数的构造方法---本次示例演示的类型
public PerClass(String name) {
this.name = name;
System.out.println("这是只有一个参数的构造方法,参数是姓名:" + name);
}
}
//接口的Lambda实现类
class mainTest {
public static void main(String[] args) {
//一个参数、参数是String的
LambdaTest01 getn = PerClass::new;
getn.getName("暇光曙墨");
}
}
以上是本篇文章的全部内容,旨在快速入门~希望能帮到诸位