如何理解 Java 8 引入的 Lambda 表达式及其使用场景

Lambda表达式是Java 8引入的一项重要特性,它使得编写简洁、可读和高效的代码成为可能。Lambda表达式本质上是一种匿名函数,能够更简洁地表示可传递的代码块,用于简化函数式编程的实现。

一、Lambda表达式概述

1. 什么是Lambda表达式

Lambda表达式是一种匿名函数,表示一段可传递的代码块,能够接受参数并返回结果。它是一种函数式接口(Functional Interface)的实例。函数式接口是仅包含一个抽象方法的接口,例如RunnableCallableComparator等。

Lambda表达式的引入旨在简化匿名内部类的使用,特别是在集合和流操作中,使代码更加简洁和易读。

2. Lambda表达式的语法

Lambda表达式的基本语法如下:

(parameters) -> expression

(parameters) -> { statements; }

具体语法形式包括:

  • 无参数() -> System.out.println("Hello, World!");
  • 一个参数,无需括号x -> x * x
  • 多个参数(x, y) -> x + y
  • 带有参数类型(int x, int y) -> x + y
  • 多行语句(x, y) -> { int sum = x + y; return sum; }

3. Lambda表达式的类型推断

Java编译器能够根据上下文推断Lambda表达式的参数类型,因此在大多数情况下,可以省略参数类型。例如:

Comparator<String> comparator = (a, b) -> a.compareToIgnoreCase(b);

在上面的例子中,编译器知道Comparator的类型参数是String,因此可以推断出ab都是String类型。

二、使用Lambda表达式的场景

1. 替代匿名内部类

Lambda表达式最常见的用途之一是替代匿名内部类,使代码更加简洁。例如,在事件处理和线程创建中,可以使用Lambda表达式代替匿名内部类。

事件处理

Java 8之前的代码:

button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("Button clicked!");}
});

使用Lambda表达式:

button.addActionListener(e -> System.out.println("Button clicked!"));
线程创建

Java 8之前的代码:

new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Thread running");}
}).start();

使用Lambda表达式:

new Thread(() -> System.out.println("Thread running")).start();

2. 集合操作

Lambda表达式在集合操作中极为有用,特别是结合Java 8引入的Stream API,可以极大地简化代码并提高可读性。

过滤和映射

Java 8之前的代码:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
List<String> filtered = new ArrayList<>();
for (String s : strings) {if (!s.isEmpty()) {filtered.add(s);}
}

使用Lambda表达式和Stream API:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
List<String> filtered = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
排序

Java 8之前的代码:

List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {@Overridepublic int compare(String a, String b) {return a.compareTo(b);}
});

使用Lambda表达式:

List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
names.sort((a, b) -> a.compareTo(b));

3. 自定义函数式接口

除了使用已有的函数式接口,我们还可以自定义函数式接口,并使用Lambda表达式进行实现。

定义函数式接口
@FunctionalInterface
interface MyFunctionalInterface {void execute();
}

使用Lambda表达式实现接口

MyFunctionalInterface myFunction = () -> System.out.println("Executing...");
myFunction.execute();

三、Java 8中的其他相关特性

1. 内置函数式接口

Java 8引入了一些常用的函数式接口,位于java.util.function包中,包括:

  • Predicate<T>:接受一个参数,返回boolean。常用于条件判断。
  • Function<T, R>:接受一个参数,返回一个结果。常用于转换操作。
  • Consumer<T>:接受一个参数,无返回值。常用于执行操作。
  • Supplier<T>:无参数,返回一个结果。常用于提供对象。
  • BinaryOperator<T>:接受两个参数,返回一个结果。常用于二元运算。
示例
// Predicate
Predicate<String> isNotEmpty = s -> !s.isEmpty();
List<String> nonEmptyStrings = strings.stream().filter(isNotEmpty).collect(Collectors.toList());// Function
Function<String, Integer> toLength = String::length;
List<Integer> lengths = strings.stream().map(toLength).collect(Collectors.toList());// Consumer
Consumer<String> print = System.out::println;
strings.forEach(print);// Supplier
Supplier<String> stringSupplier = () -> "Hello";
String s = stringSupplier.get();// BinaryOperator
BinaryOperator<Integer> sum = Integer::sum;
int result = sum.apply(1, 2);

2. 方法引用

方法引用是一种更简洁的Lambda表达式写法,用于直接引用已有的方法。方法引用的语法有四种形式:

  • 静态方法引用ClassName::staticMethod
  • 实例方法引用instance::instanceMethod
  • 特定类型的任意对象的方法引用ClassName::instanceMethod
  • 构造器引用ClassName::new
示例
// 静态方法引用
Function<String, Integer> parseInt = Integer::parseInt;// 实例方法引用
String str = "Hello";
Supplier<String> stringSupplier = str::toUpperCase;// 特定类型的任意对象的方法引用
Function<String, String> toUpperCase = String::toUpperCase;// 构造器引用
Supplier<List<String>> listSupplier = ArrayList::new;

四、Lambda表达式的优势和局限

1. 优势

  • 简洁性:Lambda表达式大大简化了代码,使代码更加简洁和易读。
  • 函数式编程:Lambda表达式支持函数式编程,使得Java能够更好地处理集合操作和并行流处理。
  • 代码重用:通过使用Lambda表达式和方法引用,可以更容易地实现代码重用。

2. 局限

  • 调试困难:由于Lambda表达式是匿名的,调试和排查问题可能比传统方法更困难。
  • 学习曲线:对于没有函数式编程背景的开发者,理解和使用Lambda表达式可能需要一些时间。
  • 性能开销:虽然Lambda表达式的性能一般较好,但在某些情况下,可能会引入额外的开销,如创建大量短命对象。

五、实战示例

以下是一个完整的示例,展示如何使用Lambda表达式和Stream API处理集合数据。

示例背景

假设我们有一个员工列表,我们需要进行以下操作:

  1. 过滤出年龄大于30的员工。
  2. 提取员工的名字。
  3. 对名字进行排序。
  4. 将名字转换为大写。
  5. 打印结果。

代码实现

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;class Employee {private String name;private int age;public Employee(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return "Employee{name='" + name + "', age=" + age + '}';}
}public class LambdaExample {public static void main(String[] args) {List<Employee> employees = Arrays.asList(new Employee("John", 25),new Employee("Jane", 35),new Employee("Jack", 40),new Employee("Jill", 22));List<String> result = employees.stream().filter(e -> e.getAge() > 30).map(Employee::getName).sorted().map(String::toUpperCase).collect(Collectors.toList());result.forEach(System.out::println);}
}

输出结果

JACK
JANE

通过这个示例,我们可以看到Lambda表达式和Stream API如何简化集合数据的处理,并使代码更加简洁和易读。

Lambda表达式是Java 8引入的一个重要特性,极大地增强了Java的表达能力和简洁性。通过Lambda表达式,开发者可以更方便地编写函数式代码,简化集合操作,提升代码的可读性和可维护性。

结合Stream API和方法引用,Lambda表达式使得Java能够更好地应对现代编程需求。尽管Lambda表达式也有其局限性,但它在提升开发效率和代码质量方面的优势是显而易见的。掌握和熟练运用Lambda表达式,对于现代Java开发者来说是必不可少的技能。

黑马程序员免费预约咨询

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/22587.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【STM32】STM32F103C6T6标准外设库

1、标准外设库获取 第一步&#xff0c;首先获取标准外设库&#xff0c;可以从官网进行下载。 https://www.st.com.cn/zh/embedded-software/stm32-standard-peripheral-libraries.html 根据自己的型号选择不同的系列&#xff0c;我这里选择是STM32F1系列 下载最新版本V3.6&a…

【QT5】<总览二> QT信号槽、对象树及样式表

文章目录 前言 一、QT信号与槽 1. 信号槽连接模型 2. 信号槽介绍 3. 自定义信号槽 二、不使用UI文件编程 三、QT的对象树 四、添加资源文件 五、样式表的使用 六、QSS文件的使用 前言 承接【QT5】&#xff1c;总览一&#xff1e; QT环境搭建、快捷键及编程规范。若存…

【最新鸿蒙应用开发】——一篇搞懂什么是UIAbility

UIAbility组件 UIAbility组件是一种包含UI的应用组件&#xff0c;UIAbility组件是系统调度的基本单元&#xff08;最小单元&#xff09;&#xff0c;为应用提供绘制界面的窗口&#xff0c;主要用于和用户交互。一个应用可以包含一个或多个UIAbility组件。 UIAbility的设计理念…

AI大模型应用开发实践:5.快速入门 Assistants API

快速入门 Assistants API Assistants API 允许您在自己的应用程序中构建人工智能助手。一个助手有其指令,并可以利用模型、工具和知识来回应用户查询。 Assistants API 目前支持三种类型的工具: 代码解释器 Code Interpreter检索 Retrieval函数调用 Function calling使用 P…

Java同步与线程安全,同步方法、同步块和java.util.concurrent包的使用

Java的同步与线程安全是并发编程中至关重要的部分。在多线程环境下&#xff0c;确保数据的一致性和避免竞态条件&#xff08;race condition&#xff09;是程序设计的关键。 一、Java中的线程安全 线程安全&#xff08;Thread Safety&#xff09;是指多线程环境下&#xff0c…

一键开启:盲盒小程序里的梦幻奇遇

在繁忙的都市生活中&#xff0c;每个人心中都藏着一个关于奇遇的梦想。如今&#xff0c;我们为您精心打造了一款盲盒小程序——“梦幻奇遇”&#xff0c;只需一键开启&#xff0c;就能带您走进一个充满无限惊喜和梦幻色彩的奇幻世界。 一、神秘盲盒&#xff0c;惊喜连连 “梦幻…

gitlab之cicd的gitlab-runner集成-dockerfile构建环境

目录 概述离线资源docker-compose问题 docker-compose问题1问题2 gitlab-runner集成gitlab 概述 cicd引文目录是想通过dockerfile构建 maven、jdk、docker环境的 gitlab-runner 运行环境。但docker最后测试的时候有点问题&#xff0c;且最后使用 kubectl 时有麻烦&#xff0c;所…

python--面向对象-文件读写-异常

一、继承 定义一个类时&#xff0c;需要使用另外一个类的方法或属性&#xff0c;就可以通过继承实现 object是Python的顶级类&#xff0c;创建类是会自动继承&#xff0c;就拥有object中的方法 定义格式 # 类的定义 # 旧式类定义 一般在定义单个类时使用 class 类名:name N…

Spring Boot 使用自定义注解和自定义线程池实现异步日志记录

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

如何保持气膜场馆内部空气新鲜—轻空间

气膜建筑作为现代建筑的一种新兴形式&#xff0c;以其独特的优势和设计受到了广泛欢迎。然而&#xff0c;保持气膜内部空气新鲜是一个必须解决的问题。我们通过配备先进的新风系统&#xff0c;提供了高效的解决方案。 新风系统的工作原理 气膜建筑内部空气的新鲜度主要依靠其配…

【vscode-快捷键 一键JSON格式化】

网上有很多JSON格式化工具&#xff0c;也有很多好用的在线json格式化工具。但是其实Vscode里面的可以直接格式化JSON&#xff0c;这里分享一个我常用的小插件 Prettify JSON 未格式化的JSON数据 召唤出命令行&#xff0c;输入prettify JSON 即可! ✿✿ヽ(▽)ノ✿

算法题:Java求数组中最大的值

采用分而治之&#xff08;二分法&#xff09;的思想去求解 分而治之&#xff1a;分而治之的思想可以用于解决很多问题&#xff0c;大概的思路就是把一个比较大的复杂的问题切分成小的块&#xff0c;然后分头去解决他们&#xff0c;最后再把结果合并起来&#xff0c;就是“分而治…

快速理解 Node.js 版本差异:3 分钟指南

Node.js 是一个广泛使用的 JavaScript 运行时环境&#xff0c;允许开发者在服务器端运行 JavaScript 代码。随着技术的发展&#xff0c;Node.js 不断推出新版本&#xff0c;引入新特性和改进。了解不同版本之间的差异对于开发者来说至关重要。以下是一个快速指南&#xff0c;帮…

C++高级 - 接口模板

目录 一. 接口 二. 模板 一. 接口 接口通常是通过抽象类或纯虚函数来实现的。 以下是一个使用抽象类来定义接口的示例代码&#xff1a; #include <iostream>class Interface { public:virtual void operation() 0; // 纯虚函数定义接口 };class ConcreteClass : pu…

【图书推荐】《Ubuntu Linux系统管理与运维实战》

本书重点 全面学习Ubuntu系统操作&#xff0c;快速掌握Linux日常管理和运维 安装和配置、桌面环境、文件系统、文件和目录管理、用户和权限管理系统的启动和关闭、服务和进程管理、软件包管理、磁盘和文件系统管理网络管理、网络服务管理、系统和网络安全 内容简介 Linux是…

计算机基础(5)——进制与进制转换

&#x1f497;计算机基础系列文章&#x1f497; &#x1f449;&#x1f340;计算机基础&#xff08;1&#xff09;——计算机的发展史&#x1f340;&#x1f449;&#x1f340;计算机基础&#xff08;2&#xff09;——冯诺依曼体系结构&#x1f340;&#x1f449;&#x1f34…

了解一下Ubuntu Linux

1.3.1 什么是Ubuntu Ubuntu这个名字非常神奇&#xff0c;它取自非洲南部祖鲁语的ubuntu&#xff0c;是一个哲学名称&#xff0c;其意思为“人性”或者“我的存在是因为大家的存在”。对于中国人来说&#xff0c;一般称呼它为乌班图。 Ubuntu是在Debian的基础上开发出来的&am…

opencv标定板图像位置

下载的C中使用的opencv库有圆点和方格的标定板图像 Opencv4.6.0\sources\doc

什么是泛洪攻击?DDos攻击也是泛洪攻击的一种?

在数字化时代的浪潮中&#xff0c;网络安全已成为一场没有硝烟的战争。其中&#xff0c;泛洪攻击作为一种常见的网络攻击手段&#xff0c;对个人用户、企业乃至国家网络安全构成了严重威胁。本文将对泛洪攻击进行深入剖析&#xff0c;包括其定义、原理、类型、影响以及应对策略…

嵌入式Linux系统编程 — 1.4 原子操作与竞争冒险

目录 1 竞争冒险 1.1 竞争冒险由来 1.2 竞争冒险理解 2 原子操作 2.1 O_APPEND 实现原子操作 2.2 pread()和 pwrite() 2.3 O_EXCL 标志创建文件 1 竞争冒险 1.1 竞争冒险由来 Linux 是一个支持多任务和多用户同时运行的操作系统&#xff0c;它允许多个进程同时执行。…