在Java8及更高版本中,Lambda表达式的引入极大地提升了编程的简洁性和效率。本文将围绕十个关键场景,展示Lambda如何助力提升开发效率,让代码更加精炼且易于理解。

集合遍历

传统的for-each循环对集合进行遍历虽然直观,但在处理大量数据时显得冗长。例如:

List<String> list = Arrays.asList("a", "b", "c");
for (String s : list) {
System.out.println(s);
}

使用Lambda表达式后,代码变得更加紧凑:

list.forEach(System.out::println);

集合排序

在以前我们对集合中的元素进行排序时,需要实现Comparable接口,或者使用Comparator比较器,在其中定义排序规则。

Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});

使用Lambda可以进行简化:

List<String> sortedList = list.sort(Comparator.comparingInt(String::length));

// 或者
Collections.sort(list, (s1, s2) -> s1.length() - s2.length()); // 或者
Collections.sort(list, Comparator.comparingInt(String::length));

集合过滤

以往的过滤操作以往需要编写繁琐的条件判断。

List<String> filterList = new ArrayList<>();
for (String s : list){
if (s.length() >= 4){
filterList.add(s);
}
}

使用Lambda可以进行简化:

List<String> filterList = list.stream().filter(e -> e.length() >= 4).collect(Collectors.toList());

关于Stream的使用方法请参考:提高Java开发生产力,我选Stream,真香啊

映射操作

如以下操作,将一个集合变成另外一个集合

List<String> upperCaseList = new ArrayList<>();
for (String str : words) {
upperCaseList.add(str.toUpperCase());
}

而Lambda表达式可用于将集合中的元素直接转换成新的形式:

List<String> upperList = list.stream().map(e -> e.toUpperCase()).collect(Collectors.toList());
upperList = list.stream().map(String::toUpperCase).collect(Collectors.toList()); List<Integer> lengthList = list.stream().map(e -> e.length()).collect(Collectors.toList());
lengthList = list.stream().map(String::length).collect(Collectors.toList());

规约操作

规约操作,即对一个集合中的元素进行求和,求平均数等

int sum = 0;
for (int num : numbers) {
sum += num;
}

使用Lambda简化

int sum = numbers.stream().mapToInt(Integer::intValue).sum();
int sum = numbers.stream().reduce(0, (n1, n2) -> n1 + n2);
int sum = numbers.stream().reduce(0, Integr::sum); List<Person> peoples = new ArrayList<>();
int ages = peoples.stream().mapToInt(Person::getAge).sum();

关于Stream的使用方法请参考:提高Java开发生产力,我选Stream,真香啊

分组操作

对一个集合基于特定规则对集合进行分组,即将List<Object>转换为Map<Object, List<Object>>

List<Person> personList = new ArrayList<>();
Map<String, List<Person>> groupMap = new HashMap<>();
for (Person person : personList) {
Integer age = person.getAge();
if (!groupMap.containsKey(age)) {
groupMap.put(age, new ArrayList<>());
}
groupMap.get(age).add(person);
}

使用Lambda简化:

Map<String, List<Person>> groupMap = words.stream()
.collect(Collectors.groupingBy(Person::age));

还有另外一种List<Object>转换为Map<Object, Object>:

List<Person> personList = new ArrayList<>();
Map<Long, Person> personMap = new HashMap<>();
for (Person person : personList) {
personMap.put(person.getId(), person);
}

使用Lambda简化:

Map<String, Person> groupMap = words.stream()
.collect(Collectors.toMap(Person::id, Function.identity(), (e1, e2) -> e1));

关于Stream的使用方法请参考:提高Java开发生产力,我选Stream,真香啊

使用函数式接口

现在有一个函数式接口:

@FunctionalInterface
interface MyInterface{
void doSomething(String s);
}

常规做法在使用函数式接口时:

MyInterface myInterface = new MyInterface() {
@Override
public void doSomething(String s) {
System.out.println(s);
}
}; myInterface.doSomething("I am 码农Academy");

使用Lamba进行优化:

MyInterface myInterface = s -> System.out.println(s);
myInterface.doSomething("I am 码农Academy");

线程创建

以往创建线程的方式:

Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello, 码农Academy!");
}
});

使用Lambda简化后:

Thread thread = new Thread(() -> System.out.println("Hello, 码农Academy!"));

// 或者使用线程池方式
ExecutorService executor = Executors.newFixedThreadPool(5); executor.execute(() -> longRunningTask());

Optional

Optional可以避免空指针异常。

Optional<String> optional = ...;
if (optional.isPresent()) {
String value = optional.get();
// 处理value
}

使用Lambda简化:

Optional<String> optional = ...;
optional.ifPresent(value -> handleValue(value));

关于使用Optional解决空指针的用法,可以参考:聊一聊日常开发中如何避免那无处不在的让人头疼的NullPointerException

Stream的流水操作

在处理业务时,我们需要对一个集合进行一系列的操作时,比如如下:

`

List<Integer> result = new ArrayList<>();
for (String str : list) {
if (str.matches("\\d+")) {
result.add(Integer.parseInt(str));
}
}

利用Stream API与Lambda结合,实现链式操作,使代码更清晰易读:

List<Integer> result = list.stream()
.filter(str -> str.matches("\\d+"))
.map(Integer::parseInt)
.collect(Collectors.toList());

比如我们使用Lambda结合Stream实现一个去重操作:

/**
* 根据学生姓名查询除重复元素
* @param students
*/
private static void repeatStudentsTest(List<Student> students){
// list 对应的 Stream
List<String> repeatStudents = students.stream()
// 获得元素出现频率的 Map,键为元素,值为元素出现的次数
.collect(Collectors.toMap(e -> e.getName(), e -> 1, Integer::sum))
// 所有 entry 对应的 Stream
.entrySet().stream()
// 过滤出元素出现次数大于 1 的 entry(过滤出来的是重复的,若这里条件是等于,即可达到去重的目的)
.filter(entry -> entry.getValue()>1)
// 获得 entry 的键(重复元素)对应的 Stream
.map(entry -> entry.getKey())
// 转化为 List
.collect(Collectors.toList()); repeatStudents.forEach(repeatStudent -> {
System.out.println(repeatStudent);
});
}

Lambda的断点调试

关于使用Idea开发式,以前对代码断点时确实无法进入到lamda表达式里面,但是随着Idea的升级,已经解决了这个问题,可以在Lambda表达式的内部进行断点

Lambda易读

有人可能会认为Lambda表达式的代码阅读起来有些吃力,当然也是可以理解,其主要原因有如下几个方面:

  1. 匿名性:Lambda表达式本质上是匿名函数,没有显式的方法名称,因此,初次接触或不熟悉其语法的读者可能难以快速理解其意图,尤其是在较复杂的上下文中。

  2. 简洁性:Lambda表达式的目的是为了简化代码,它往往非常紧凑,可能会把原本分散在多个行或方法中的逻辑压缩到一行甚至一部分内。这样的代码密度可能导致理解上的难度,特别是当逻辑较为复杂时。

  3. 抽象层次:Lambda表达式常与函数式接口一起使用,这意味着理解Lambda表达式需要知道它所对应接口的行为约定。如果读者不了解接口的具体功能,那么Lambda表达式就可能变得难以解读。

  4. 函数式编程范式:对于习惯于命令式编程风格的开发者来说,函数式编程的思维方式和Lambda表达式的使用可能需要一定适应期。尤其是涉及到闭包、高阶函数等概念时,如果不熟悉这些概念,理解Lambda表达式的逻辑会更加困难。

  5. 依赖上下文:Lambda表达式经常用于流(Stream)操作、事件监听、回调函数等场景,其含义高度依赖于上下文环境。在缺少充分注释或文档的情况下,阅读者可能需要花费更多精力去推理其作用。

但是,随着Java 8以来函数式编程特性的普及,越来越多的Coder们开始接受并熟练使用Lambda表达式。适当的代码组织、注释和遵循良好的编程规范有助于降低Lambda表达式带来的阅读障碍。并且随着经验的增长和技术背景的丰富,我们会逐渐认识到Lambda表达式的优点,即它可以增强代码的可读性和简洁性,尤其在处理数据流和进行函数组合时。

总结

熟练运用Lambda表达式能够显著提升代码质量与开发效率,使得代码逻辑更加简明扼要,同时也增强了程序的可读性与维护性。不断学习和实践这些技巧,你的开发效率必将迎来质的飞跃。并且Lambda与Stream一起使用才能发挥他们最大的优点。关于Stream的使用方法请参考:提高Java开发生产力,我选Stream,真香啊

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等

提高生产力!这10个Lambda表达式必须掌握,开发效率嘎嘎上升!的更多相关文章

  1. Lambda表达式在Android开发中的应用

    在Java8中拥有Lambda表达式的新功能,如果现在Android项目中使用,首先,必须在项目中的build.gradle配置一下 使用Lambda表达式必须满足只有一个待实现方法这个规则,否则就不 ...

  2. Java 8特性探究(1):通往lambda之路与 lambda表达式10个示例

    本文由 ImportNew 函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是只包含一个方法的接口.比如Java标准库中的ja ...

  3. Java 8 Lambda表达式10个示例【存】

    PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是 ...

  4. java8 快速入门 lambda表达式 Java8 lambda表达式10个示例

    本文由 ImportNew - lemeilleur 翻译自 javarevisited.欢迎加入翻译小组.转载请见文末要求. Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发 ...

  5. Java8 lambda表达式10个示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Ja ...

  6. Java基础学习总结(44)——10个Java 8 Lambda表达式经典示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Ja ...

  7. Java8 lambda表达式10个示例<转>

    例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runna ...

  8. 【Java学习笔记之三十一】详解Java8 lambda表达式

    Java 8 发布日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Java 8之前 ...

  9. 将简单的lambda表达式树转为对应的sqlwhere条件

    1.Lambda的介绍 园中已经有很多关于lambda的介绍了.简单来讲就是vs编译器给我带来的语法糖,本质来讲还是匿名函数.在开发中,lambda给我们带来了很多的简便.关于lambda的演变过程可 ...

  10. jdk8 lambda表达式总结

    Java8 lambda表达式10个示例   1. 实现Runnable线程案例 使用() -> {} 替代匿名类: //Before Java 8: new Thread(new Runnab ...

随机推荐

  1. Go微服务框架go-kratos实战学习07:consul 作为服务注册和发现中心

    一.Consul 简介 consul 是什么 HashiCorp Consul 是一种服务网络解决方案,它能够管理服务之间以及跨本地和多云环境和运行时的安全网络连接.Consul 它能提供服务发现.服 ...

  2. Android加载PDF方案(pdf.js,支持缩放)

    都知道,Android本身的webview是不支持pdf加载的(比不上iOS的webview,谁让人家NB呢),因此通过连接Google的一个服务器转换成功后返回给WebView显示.但是,但是,但是 ...

  3. 硬件开发笔记(十一):Altium Designer软件介绍、安装过程和打开pcb工程测试

    前言   前面做高速电路,选择是阿li狗,外围电路由于读者熟悉AD,使用使用ad比较顺手,非高速电路就使用AD了,其实AD也可以做高速电路,由于笔者从13年开始做硬是从AD9开始的,所以开始切入AD做 ...

  4. python中如何使两个序列相加不改变内存地址的几种方式

    # 方式1 a = [1,2,3] print(a) # 4551311680 a.extend([4,5]) print(a) # 4551311680 # 方式2 b = [1,2,3] prin ...

  5. 【Azure 云服务】Azure Cloud Service 关于虚拟机资源,杀毒软件配置,补丁机制的问答

    一:云服务后端是2台虚拟机,Work Role,Web Role,可以RDP进去,但是为什么在虚拟机列表里看不到呢? 因为云服务(经典)是PaaS服务,有别于传统的IaaS服务,其提供的WebRole ...

  6. [C++逆向] 7 变量在内存中的位置和访问方式

    目录 全局变量和局部变量的区别 局部静态变量 有意思的 堆变量 变量类型 作用域 可访问 全局变量 进程作用域 整个进程可访问 静态变量 文件作用域 当前代码文件可访问 局部变量 函数作用域 函数内可 ...

  7. Educational Codeforces Round 65 (Rated for Div. 2)C. News Distribution(模拟,计算的时候去重)

    这道题目明显和出现4次的数和出现2次的数的个数有关系,只需要在每次更新之后维护这两个信息即可,我们在算出现2次的数的个数时其实会把出现4次的数的个数会把出现2次的数的个数+2,在判断时需要考虑这一点. ...

  8. Server-side template injection 模板注入问题总结

    概念: 服务器模板注入(Server-side template injection) 攻击者能够使用本地的模板语法去注入一个恶意的payload,然后在服务器端执行该攻击,当与欧股直接输入数据到模板 ...

  9. Delete `␍`

    新电脑遇到的问题 Delete `␍`eslint(prettier/prettier) 网上一搜,一堆解决办法,没有一个说到点子上,都是表面上如何避免,如何设置VSCODE... 都知道是换行符的问 ...

  10. acme.sh 免费泛解析证书生成

    环境准备 本篇文章使用的 ACME 客户端是基于 Docker 容器使用的,所以需要准备 Docker 运行环境.本文使用的是 CentOS 7.x 与 Docker CE - 19.03.13,且已 ...