OneCoder Avatar
OneCodercoderli.com · 937 篇博文
{ } Java

Java 服务端架构

Spring、Netty、日志框架与工程化实战

🎨 视觉封面

一起学Java(15)-[JDK篇]教你了解Java8特性,学习Lambda表达式

📅 2024-10-23·✍️ onecoder·计算中...·⏱️ 10 分钟
#Java#JDK#一起学Java

在文章《2024年主流使用的JDK版本及其核心特性介绍》中,我们详细介绍了Java8、Java11、Java17等主流Java版本主要新增特性。针对其中的一些核心特性,展开研究一二。

Lambda 表达式 (JEP 126) 详细介绍

Lambda 表达式是 Java 8 引入的一个重要新特性,它允许将函数作为参数传递,并简化了代码的表达方式。Lambda 表达式通常用于表达行为,而不需要定义完整的类或匿名内部类。Lambda 表达式最常见的用法是在集合和流(Stream)API中进行数据操作(Stream API (JEP 107) 流 API)。

1. Lambda 表达式的设计定位

Lambda 表达式的设计目的是简化函数式编程风格的实现,特别是针对单方法接口(即只有一个抽象方法的接口,通常被称为函数式接口)。在引入Lambda表达式之前,匿名内部类是处理回调或简短行为的常用手段,但它的语法冗长且复杂。

设计目标:

  • 简化代码表达:减少样板代码(boilerplate code)的编写,例如匿名内部类的定义。
  • 提高代码可读性:使代码更清晰、更简洁。
  • 支持函数式编程:允许将函数作为参数传递或返回,使得编程更加灵活。

核心概念:

  • 函数式接口:任何只包含一个抽象方法的接口都可以用 Lambda 表达式来实现。例如 java.lang.Runnablejava.util.Comparator 等。
  • 行为参数化:可以通过 Lambda 表达式传递行为(函数),避免传统通过类继承或接口实现来传递行为的方式。

2. Lambda 表达式的语法和原理

Lambda 表达式的语法形式如下:

JAVA
(parameters) -> expression
或者
(parameters) -> { statements }

语法说明

  • 参数列表:Lambda 表达式的输入参数,可以有多个参数,如果只有一个参数,圆括号可以省略。
  • 箭头符号(->:分隔参数和Lambda体。
  • Lambda体:可以是一个表达式或者多个语句。如果是一个表达式,可以省略花括号和返回值。

3. Lambda 表达式的用法

(1) 函数式接口-无参数

Lambda 表达式只能用于实现函数式接口。函数式接口是只有一个抽象方法的接口,可以通过 @FunctionalInterface 注解显式声明一个接口为函数式接口。

示例:

JAVA
package com.coderli.one.jdk8.lambda;

@FunctionalInterface
public interface LambdaFunctionalInterfaceDemo {
    void doSomething();
}

在这个例子中,MyFunctionalInterface 是一个函数式接口,它只有一个抽象方法 doSomething,因此可以使用 Lambda 表达式来实现它。如:

JAVA
LambdaFunctionalInterfaceDemo lambdaDemo = () -> System.out.println("Do something.");
lambdaDemo.doSomething();

运行结果

BASH
Do something.

再例如:

JAVA
Runnable r = () -> System.out.println("Running in a separate thread");
new Thread(r).start();

等同于:

JAVA
Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("Running in a separate thread");
    }
};

(2) 函数式接口-有参数

接口定义如下

JAVA
package com.coderli.one.jdk8.lambda;

public interface LambdaInterfaceDemo {
    void doSomething(String name);
}

Lambda实现

JAVA
LambdaInterfaceDemo lambdaInterfaceImpl = (name) -> System.out.println("LambdaInterface: " + name);
lambdaInterfaceImpl.doSomething("Lambda Demo");

运行结果:

BASH
LambdaInterface: Lambda Demo

(3) 在集合中的应用

Lambda 表达式和集合的组合通常通过 Stream API 来操作集合数据。这大大简化了对集合的过滤、映射和归约操作。

示例:

JAVA
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 使用 Lambda 表达式过滤
List<String> filteredNames = names.stream()
    .filter(name -> name.startsWith("A"))
    .collect(Collectors.toList());

System.out.println(filteredNames);

输出:

BASH
[Alice]

(4) 使用 forEach 简化遍历

在没有 Lambda 表达式的情况下,我们通常使用 for 循环来遍历集合:

JAVA
for (String name : names) {
    System.out.println(name);
}

使用 Lambda 表达式,集合的遍历可以简化为:

JAVA
names.forEach(name -> System.out.println(name));

(5) 方法引用

Lambda 表达式还支持方法引用,可以直接引用现有方法作为 Lambda 表达式的实现。

示例:

JAVA
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
names.forEach(System.out::println);

这段代码与 names.forEach(name -> System.out.println(name)); 等效。

4. Lambda 表达式的内部原理

Lambda 表达式的原理基于匿名类的优化,但它并不直接生成匿名类对象,而是通过 Java 的动态方法调用技术实现,具有更高效的运行时性能。具体来说,Lambda 表达式通过 invokedynamic 字节码指令,在运行时动态生成目标方法的实现。

  • 目标类型:Lambda 表达式会推断其对应的函数式接口类型,称为目标类型。
  • 捕获变量:Lambda 表达式可以使用外部作用域中的变量,但这些变量必须是最终的(final)或者有效最终的(effectively final),即这些变量一旦赋值后不会再被修改。

总结

  • 设计定位:Lambda 表达式用于简化函数式接口的实现,减少样板代码,支持行为参数化。
  • 原理:通过动态方法调用,Lambda 表达式避免了传统匿名类的性能开销,并通过目标类型推断实现了灵活性。
  • 用法:常用于集合操作、事件处理等场景,通过简化的语法使代码更具可读性和可维护性。

以上只能算对Lambda表达式的一个简单介绍。Lambda表达式作为Java 8引入的重要特性,其应用范围非常广泛,涉及的内容也相当丰富。在实际开发中,我们还需要深入理解Lambda表达式的更多细节,如变量捕获、方法引用的不同形式、与Stream API的结合使用等。同时,合理使用Lambda表达式可以大大提高代码的简洁性和可读性,但过度使用也可能导致代码难以理解。因此,在实际应用中,我们需要权衡代码的简洁性和可读性,选择最适合的方式来使用Lambda表达式。


所有代码已上传至:https://github.com/lihongzheshuai/java-all-in-one

💡 OneCoder 资源指引

所有代码开源上传至 GitHub:yummy-code 仓库 · GESP 专题站:GESP WIKI

🤝 技术交流与答疑

欢迎加入:C++ GESP/CSP 考级答疑群(688906745)Java/Python交流群(982860385),点击可直接加群。

📚

猜你想读 · 相关文章推荐

Java 架构演进与实战 · (3)JDK篇⏱️ 17 分钟

一起学Java(22)-[JDK篇]学习Java中String的字符编码和代理对机制

上文《一起学Java(21)-[配置篇]Gradle控制台乱码问题配置和解决》中,我们解决了Gradle控制台字符乱码问题,这个问题实际是在研究Java String的字符编码机制时产生的。本文回归正题,研究下Java中String的字符编码和代理对机制。

阅读全文 →
Java 架构演进与实战 · (1)起步搭建篇⏱️ 14 分钟

一起学Java(1)-[起步篇]教你如何创建一个Gradle管理的Java开源项目(java-all-in-one)

一时兴起,也为了便于跟大家同步学习进展和分享样例代码,遂决定创建一个全新的Java项目,并通过Github与大家分享。本文就是记录该项目的创建过程以及其中的一些知识要点(如Gradle等)。为了紧跟技术潮流和提高操作效率,本项目通过IDEA直接创建,用Gradle进行配置管理和用Git进行版本管理,并托管到Github...

阅读全文 →
Java 架构演进与实战 · (1)起步搭建篇⏱️ 5 分钟

一起学Java(2)-[起步篇]教你如何利用Github fork一起进行开源项目协作

在第一步中(一起学Java(1)-新建一个Gradle管理的Java项目)我们已经完成了项目的创建并托管到了Github上。现在自然要首先解决同学们如何下载代码和进行代码同步更新和联系的问题。这就涉及到Git的fork理念和协作模式的问题。具体介绍如下。

阅读全文 →
OneCoder

OneCoder (lihongzheshuai)

一个中年人的自留地,记录学习 C++、GESP/NOI、Java、Python 与算法架构的心得体会。本站唯一网址:coderli.com

💬 读者留言与交流

0 条讨论
✨ 支持 Markdown 语法格式
还没有留言,快来成为第一个讨论者吧!