2024年Java最新Java Lambda表达式(1),java技术经理面试题

最后

看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面

小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>

image

针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺

image

全都是一丢一丢的收集整理纯手打出来的

更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

image

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 多个参数

  • 指定参数类型

  • Java 11中的var参数类型

  • Lambda表达式主体

  • Lambda表达式返回值

  • Lambdas作为对象

  • 变量捕获

    • 局部变量捕获
  • 实例变量捕获

  • 静态变量捕获

  • Lambda方法引用

    • 静态方法引用
  • 参数方法引用

  • 实例方法引用

  • 构造方法引用

Java Lambda表达式是Java8中的新特性。Java lambda表达式是Java进入函数式编程的第一步。因此,Java lambda表达式是可以单独创建的函数,而无需属于任何类。Java lambda 表达式可以像对象一样传递并按需执行。

Java lambda表达式通常用于实现简单的事件监听/回调,或在Java Streams API 函数式编程时使用。

Java Lambdas和函数式接口

====================================================================================

函数式编程通常用于实现事件监听器。Java中的事件监听器通常被定义为具有一个抽象方法的Java接口。

这是一个模拟的单个抽象方法接口示例:

public interface StateChangeListener {

public void onStateChange(State oldState, State newState);

}

这个Java接口定义了一个抽象方法,只要状态发生变化(无论观察到什么),都将调用该方法。

在Java 7中,你必须实现此接口才能监听状态的更改。假设你有一个名为StateOwner的类,可以注册状态监听器。示例如下:

public class StateOwner {

public void addStateLister(StateChangeListener stateChangeListener) {

//do some thing

};

}

在Java 7中,你可以使用匿名接口实现添加监听器,如下所示:

StateOwner stateOwner = new StateOwner();

stateOwner.addStateLister(new StateChangeListener() {

@Override

public void onStateChange(State oldState, State newState) {

System.out.println(“State changed”);

}

});

在Java 8中你可以使用Lambda表达式来添加监听器,如下:

StateOwner stateOwner = new StateOwner();

stateOwner.addStateLister(

(oldState, newState) -> System.out.println(“State change”)

);

这一部分是Lambda表达式:

(oldState, newState) -> System.out.println(“State changed”)

lambda表达式与addStateListener()方法的参数的参数类型匹配。如果lambda表达式与参数类型(在本例中为StateChangeListener接口)匹配,则将lambda表达式转换为实现与该参数相同的接口的函数。

Java lambda表达式只能在它们匹配的类型是单个方法接口的地方使用。

在上面的示例中,lambda表达式作为参数,其中参数类型为StateChangeListener接口。该接口只有一个抽象方法。因此,lambda表达式成功匹配该接口。

将Lambda匹配到接口


**单个抽象方法接口有时也称为函数式接口。**将Java lambda表达式与函数式接口进行匹配需要以下步骤:

  • 接口是否只有一个抽象方法?

  • lambda表达式的参数是否与抽象方法的参数匹配?

  • lambda表达式的返回类型是否与抽象方法的返回类型匹配?

如果这三个条件都满足,则该接口可以匹配给定的lambda表达式。

具有默认方法和静态方法的接口


从Java 8开始,Java接口可以包含默认方法和静态方法。默认方法和静态方法都可以在接口中直接实现。这意味着,Java lambda表达式可以使用多种方法实现接口——只要该接口仅有一个抽象方法即可(函数式接口)。

可以使用lambda表达式实现以下接口:

import java.io.IOException;

import java.io.OutputStream;

public interface MyInterface {

void printIt(String text);

default public void printUtf8To(String text, OutputStream outputStream){

try {

outputStream.write(text.getBytes(“UTF-8”));

} catch (IOException e) {

throw new RuntimeException(“Error writing String as UTF-8 to OutputStream”, e);

}

}

static void printItToSystemOut(String text){

System.out.println(text);

}

}

即使此接口包含3个方法,也可以通过lambda表达式实现,因为只有一个抽象方法。

实现如下:

MyInterface myInterface = (String text) -> {

System.out.print(text);

};

Lambda表达式 vs 匿名接口实现

=====================================================================================

即使lambda表达式类似于匿名接口实现,但也有一些区别需要注意。

最主要的区别,匿名接口实现可以具有状态(成员变量),而lambda表达式则不能。

看一下下面这个接口:

public interface MyEventConsumer {

public void consume(Object event);

}

可以使用匿名接口实现方式来实现此接口,如下所示:

MyEventConsumer consumer = new MyEventConsumer() {

public void consume(Object event){

System.out.println(event.toString() + " consumed");

}

};

此匿名MyEventConsumer实现可以具有自己的内部状态。

重写匿名接口实现:

MyEventConsumer myEventConsumer = new MyEventConsumer() {

private int eventCount = 0;

public void consume(Object event) {

System.out.println(event.toString() + " consumed " + this.eventCount++ + " times.");

}

};

请注意,匿名MyEventConsumer接口实现现在具有一个名为eventCount的属性。

Lambda表达式不能具有此类属性。因此,lambda表达式是无状态的。

Lambda类型推断

============================================================================

在Java 8之前,在进行匿名接口实现时,必须指定要实现的接口。这是本文开头的匿名接口实现示例:

stateOwner.addStateListener(new StateChangeListener() {

public void onStateChange(State oldState, State newState) {

// do something with the old and new state.

}

});

使用lambda表达式时,通常可以从相关的代码中推断出类型。例如,可以从addStateListener()方法(StateChangeListener接口上的抽象方法)的方法声明中推断参数的接口类型。

这称为类型推断。编译器通过在其他地方寻找类型来推断参数的类型——在这种情况下为方法定义。这是本文开头的示例,lambda表达式中并未声明参数的类型:

stateOwner.addStateListener(

(oldState, newState) -> System.out.println(“State changed”)

);

在lambda表达式中,通常可以推断参数类型。在上面的示例中,编译器可以从onStateChange()方法声明中推断其类型。因此,从onStateChange()方法的方法声明中就可以推断出参数 oldState 和 newState 的类型。

Lambda参数

==========================================================================

由于Java lambda表达式实际上只是方法,因此lambda表达式可以像方法一样接受参数。前面显示的lambda表达式的(oldState,newState)部分指定lambda表达式使用的参数。这些参数必须与函数式接口的抽象方法参数匹配。在当前这个示例,参数必须与StateChangeListener接口的onStateChange()方法的参数匹配:

public void onStateChange(State oldState, State newState);

首先,lambda表达式中的参数数量必须与方法匹配。

其次,如果你在lambda表达式中指定了任何参数类型,则这些类型也必须匹配。我还没有向你演示如何在lambda表达式参数上设置类型(本文稍后展示),但是在大多数情况下,你不会用到它。

无参数


如果lambda表达式匹配的方法无参数,则可以这样写lambda表达式:

() -> System.out.println(“Zero parameter lambda”);

请注意,括号中没有内容。那就是表示lambda不带任何参数。

一个参数


如果Java lambda表达式匹配的方法有一个参数,则可以这样写lambda表达式:

(param) -> System.out.println("One parameter: " + param);

请注意,参数在括号内列出。

当lambda表达式是单个参数时,也可以省略括号,如下所示:

param -> System.out.println("One parameter: " + param);

多个参数


如果Java lambda表达式匹配的方法有多个参数,则需要在括号内列出这些参数。代码如下:

(p1, p2) -> System.out.println("Multiple parameters: " + p1 + ", " + p2);

仅当方法是单个参数时,才可以省略括号。

指定参数类型


如果编译器无法从lambda匹配的函数式接口抽象方法推断参数类型,则有时可能需要为lambda表达式指定参数类型。不用担心,编译器会在这种情况下会有提醒。这是一个Java lambda指定参数类型示例:

(Car car) -> System.out.println("The car is: " + car.getName());

如你所见,car参数的类型(Car)写在参数名称的前面,就像在其他方法中声明参数或对接口进行匿名实现时一样。

Java 11中的var参数类型


在Java 11中,你可以使用var关键字作为参数类型。

var关键字在Java 10中作为局部变量类型推断引入。从Java 11开始,var也可以用于lambda参数类型。这是在lambda表达式中使用Java var关键字作为参数类型的示例:

Function<String, String> toLowerCase = (var input) -> input.toLowerCase();

Lambda表达式主体

=============================================================================

lambda表达式的主体以及它表示的函数/方法的主体在lambda声明中的->的右侧指定:

这是一个示例:

(oldState, newState) -> System.out.println(“State changed”)

如果你的lambda表达式需要包含多行,则可以将lambda函数主体括在{}括号内,Java在其他地方声明方法时也需要将其括起来。这是一个例子:

(oldState, newState) -> {

System.out.println("Old state: " + oldState);

System.out.println("New state: " + newState);

}

Lambda表达式返回值

==============================================================================

你可以从Java lambda表达式返回值,就像从方法中返回值一样。你只需向lambda表达式主体添加一个return,如下所示:

(param) -> {

System.out.println("param: " + param);

return “return value”;

}

如果你的lambda表达式只需要计算一个返回值并将其返回,则可以用更短的方式指定返回值。例如这个:

(a1, a2) -> { return a1 > a2; }

你可以写成:

(a1, a2) -> a1 > a2;

然后,编译器会断定表达式 a1> a2 是lambda表达式的返回值。

Lambdas作为对象

=============================================================================

Java lambda表达式本质上是一个对象。你可以将变量指向lambda表达式并传递,就像处理其他任何对象一样。这是一个例子:

public interface MyComparator {

public boolean compare(int a1, int a2);

}

MyComparator myComparator = (a1, a2) -> return a1 > a2;

boolean result = myComparator.compare(2, 5);

第一个代码块显示了lambda表达式实现的接口。

第二个代码块显示了lambda表达式的定义,lambda表达式如何分配给变量,以及最后如何通过调用其实现的接口方法来调用lambda表达式。

变量捕获

======================================================================

在某些情况下,Java lambda表达式能够访问在lambda表达式主体外部声明的变量。

Java lambdas可以捕获以下类型的变量:

  • 局部变量

  • 实例变量

  • 静态变量

这些变量捕获的每一个将在以下各节中进行描述。

局部变量捕获


Java lambda可以捕获在lambda主体外部声明的局部变量的值。为了说明这一点,首先看一下这个函数式接口:

public interface MyFactory {

public String create(char[] chars);

}

现在,看一下实现MyFactory接口的lambda表达式:

总结

总的来说,面试是有套路的,一面基础,二面架构,三面个人。

最后,小编这里收集整理了一些资料,其中包括面试题(含答案)、书籍、视频等。希望也能帮助想进大厂的朋友

三面蚂蚁金服成功拿到offer后,他说他累了

三面蚂蚁金服成功拿到offer后,他说他累了

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

====================================================================

在某些情况下,Java lambda表达式能够访问在lambda表达式主体外部声明的变量。

Java lambdas可以捕获以下类型的变量:

  • 局部变量

  • 实例变量

  • 静态变量

这些变量捕获的每一个将在以下各节中进行描述。

局部变量捕获


Java lambda可以捕获在lambda主体外部声明的局部变量的值。为了说明这一点,首先看一下这个函数式接口:

public interface MyFactory {

public String create(char[] chars);

}

现在,看一下实现MyFactory接口的lambda表达式:

总结

总的来说,面试是有套路的,一面基础,二面架构,三面个人。

最后,小编这里收集整理了一些资料,其中包括面试题(含答案)、书籍、视频等。希望也能帮助想进大厂的朋友

[外链图片转存中…(img-9wThIxRW-1714909579012)]

[外链图片转存中…(img-4VvVNdFq-1714909579012)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值