Javajdk8新特性中lambda 详解

news/2024/7/7 20:59:46

Java 8 开始支持 lambda 表达式,是 Java 编程语言中对函数式编程的一种支持。Lambda 表达式也被称为闭包或匿名函数,可以让开发者轻松地写出简单而强大的代码,并带来显著的性能优势和更好的可读性。本文将详细介绍 Java Lambda 的概念、语法、使用方法以及适用场景等相关内容,帮助您充分了解并掌握该技术。

一、Lambda表达式基础知识

什么是 Lambda 表达式? Lambda 表达式实际上是一种匿名方法,它没有名称、修饰符和返回类型声明。Lambda 表达式可以传递到方法中,作为参数或返回值,或者存储在变量中。语法格式如下:

(args) -> { expression; }

或

(args) -> return statement;

为什么需要 Lambda 表达式?
Lambda 表达式可以极大地简化代码,并且可以提高代码的性能。在使用 Lambda 表达式时,可以不需要使用功能接口(Functional Interface)的实现类,从而省去了重复代码和编程工作量。同时,Lambda 表达式所带来的语法简化和代码优化也可以使代码更有可读性。

什么是 Functional Interface?
Functional Interface(函数接口)是 Java8 中定义的一种特殊概念,它描述的是一个只包含单个抽象方法的接口。Lambda 表达式被设计成只能与函数接口相关联,这意味着如果想使用 Lambda 表达式,必须有一个与之对应的函数式接口。Java 8 为我们提供了很多的预置接口,比如 Runnable 接口、Predicate 接口、Function 接口等。

二、Lambda 表达式语法

无参Lambda表达式 当Lambda表达式中没有任何参数时,小括号内留空即可,代码示例如下:
() -> System.out.println(“Hello, world!”);

有参Lambda表达式 当Lambda表达式中有一个以上的参数,多个参数之间用逗号隔开,仍需使用小括号将参数包围,代码示例如下:

(String s) -> System.out.println(s);

多行Lambda表达式 当Lambda表达式体内涉及多条语句时,使用花括号 {} 括起来,并使用分号 ; 分隔语句即可,代码示例如下:

(int x, int y) -> {
System.out.println("Input values: " + x + ", " + y);
return x + y;
}

带返回值的 Lambda 表达式 在 Lambda 表达式中使用 return 关键字来返回某个值,比如:

(String s) -> {
return "Hello, " + s;
}

当 Lambda 表达式只有一行语句时,可以省略花括号和 return。其中,该行语句既是表达式的返回值。例如:

(String s) -> "Hello, " + s;

方法引用 Lambda 表达式可转化为方法引用(Method Reference),简化了 Lambda 表达式的书写过程。举例如下:

System.out::println;

其中,System.out 对应实例对象,println 对应方法名。

三、Lambda 表达式使用方法

在 Java 集合中使用 Lambda 表达式
Java 集合提供了很多便于使用 Lambda 表达式的函数接口,比如 forEach()、map()、reduce()、filter() 等。通过使用 Lambda 表达式,可以大大简化这些接口的实现逻辑,从而更加方便地完成对集合的操作。

作为参数传递给函数或方法:
将 Lambda 表达式作为参数传递给函数或方法,能够大大减少样板代码并简化程序结构。举例,考虑一个排序程序,借助 Lambda 表达式可以让排序的逻辑更加清晰:

Arrays.sort(names, (String a, String b) -> {
return b.compareTo(a);
});

创建线程 在 Java 中,创建新线程需要实例化 Thread 类或可行性 Runnable 接口。Lambda 表达式可以使线程管理变得更加容易和便捷:

Thread t = new Thread(() -> {
System.out.println("New thread created.");
});
t.run();

四、Lambda表达式适用场景

Lambda 表达式适用于各种需要传递函数作为参数的场景,主要包括以下几个方面:

1.集合操作:Lambda 表达式可以很方便地用于对集合进行过滤、排序、转换等操作。例如,我们可以使用 Lambda 表达式来实现比较器对象,从而进行集合排序。

2.观察者模式:在需要实现简单的观察者模式时,可以使用 Lambda 表达式来代替传统的匿名内部类。这样可以使得代码更加简洁明了,并且提高了可维护性和可读性。

3.线程处理:Lambda 表达式可以通过 Java 8 中新增的函数式接口 Runnable 和 Callable 来创建新线程或者提交任务到线程池。这种方式更加简单灵活,也方便线程处理的异常处理。

4.模板方法设计模式:Lambda 表达式可以作为参数传递给通用代码中的抽象方法,从而使得代码更加灵活可扩展。

5.GUI应用程序:在使用基于事件机制的图形用户界面 GUI 开发时,可以使用 Lambda 表达式处理事件响应,避免编写复杂的匿名内部类。

总结来说,Lambda 表达式适用于需要传递函数作为参数的各种场景中,并且可以大大提高代码的简洁性、可读性和可维护性。我们可以根据具体业务需求,灵活地运用 Lambda 表达式,同时注意在性能优化方面进行相应的设计和改进。

五、Lambda表达式示例

示例1:使用 Lambda 实现 Comparator 接口

首先定义一个 Person 类:

public class Person {
    private String name;
    private int age;
    
    // 构造函数
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter 和 setter 略...

}

使用 Lambda 表达式实现 Comparator 接口,按照年龄对 Person 列表进行排序:

List<Person> personList = new ArrayList<>();
personList.add(new Person("Amy", 18));
personList.add(new Person("Bob", 22));
personList.add(new Person("Chris", 20));

Collections.sort(personList, (p1, p2) -> p1.getAge() - p2.getAge());

for (Person person : personList) {
    System.out.println(person.getName() + ": " + person.getAge());
}

输出结果为:

Amy: 18
Chris: 20
Bob: 22

示例2:使用 Lambda 实现 Runnable 接口

实现 Runnable 接口是 Java 中创建线程的一种方式,在 Java 8 中可以通过 Lambda 表达式来实现这一接口。

Thread thread = new Thread(() -> {
    for (int i = 0; i < 10; i++) {
        System.out.println("Thread run " + i);
    }
});
thread.start();

输出结果为:

Thread run 0
Thread run 1
Thread run 2
Thread run 3
Thread run 4
Thread run 5
Thread run 6
Thread run 7
Thread run 8
Thread run 9

示例3:使用 Lambda 实现 forEach 方法

Iterable 接口中的 forEach 方法可以很方便地实现对集合或者数组中每个元素的遍历操作。在 Java 8 中,我们可以直接传入 Lambda 表达式来实现这一功能。

List<String> list = Arrays.asList("Java", "Python", "C++");
list.forEach(str -> System.out.println(str));

输出结果为:

Java
Python
C++

示例4:使用 Lambda 实现并行流处理

并行流是一个在 Java 8 中新增的特性,可以让我们方便地利用 CPU 的多核心来加速数据处理任务。在使用 Lambda 表达式时,只需要将 sequential() 方法替换成 parallel() 方法即可开启并行处理。

下面以求平均数为例,展示如何使用 Lambda 实现并行流处理:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

double average = numbers.parallelStream()
                        .mapToInt(i -> i)
                        .average()
                        .getAsDouble();

System.out.println(average);

输出结果为:

5.5

示例5:使用 Lambda 实现 Stream 的 filter 和 map 方法

Stream 类中的 filter 和 map 方法可以实现对流中元素的筛选和转换操作。在 Java 8 中,我们可以利用 Lambda 表达式来完成这一功能。

下面以将字符串全部变成大写为例,展示如何使用 Lambda 实现 filter 和 map 方法:

List<String> stringList = Arrays.asList("Java", "Python", "C++");

List<String> upperCaseList = stringList.stream()
                                    .filter(str -> str.length() > 3)
                                    .map(str -> str.toUpperCase())
                                    .collect(Collectors.toList());

System.out.println(upperCaseList);

输出结果为:

[JAVA, PYTHON]

六、Lambda表达式优缺点

优点:

1.更简洁的代码:Lambda 表达式能够代替传统的匿名内部类,可以大大减少代码行数,并且让代码更加清晰明了。

2.函数式风格:Lambda 表达式支持函数式风格编程,即将方法作为参数进行传递,从而实现更加灵活的编程方式。

3.可重用性:Lambda 表达式可以非常方便地在各种集合、数组等容器中使用,也可以在多个地方重用同一个 Lambda 表达式,提高代码的复用性。

4.并发能力:通过使用 Stream API 和并行流处理,Lambda 表达式可以帮助我们更加轻松地并行化处理计算任务,提高程序的运行效率。

缺点:

1.学习难度增加:Lambda 表达式需要理解更加抽象的函数式编程思想,初学者可能需要一定时间来掌握这项新特性。

2.语法繁琐:Lambda 表达式虽然可以减少代码行数,但有些场景下也需要繁琐的语法结构来实现。

3.性能问题:Lambda 表达式在确保代码简洁的同时,可能会对程序的性能造成一定的损失,例如遍历过程中进行过多的装箱和拆箱操作。

4.缺少可读性:Lambda 表达式虽然可以使得代码更加简洁,但在一些复杂的情况下,Lambda 表达式会让代码变得难以阅读和理解。

七、Lambda表达式的性能

Lambda 表达式的性能与传统的匿名内部类相比,可能会稍微降低一些性能。主要原因包括以下几点:

1.对象创建:在使用 Lambda 表达式时,需要创建一个函数式接口的实例对象,这个过程需要进行对象的创建和初始化,而在传统的匿名内部类中,由于不需要额外的函数式接口,所以不需要进行对象的创建和初始化。

2.捕获上下文:Lambda 表达式可以访问父类作用域的变量,这需要将这些变量捕获到 Lambda 表达式中,并在每次调用时传递给 Lambda 表达式,这个过程也会对性能造成一定影响。

3.代码生成:在编译时,Lambda 表达式会被转换为一个方法,并生成一个动态类的实例,在运行时通过反射的方式进行调用。而在传统的匿名内部类中,由于它们是单独的类,所以不存在这个问题。

虽然 Lambda 表达式相对于传统的匿名内部类会带来一定程度的性能损失,但这种损失往往只是微不足道的,在新版本的 Java 中也会进行优化,并尝试将性能优化至与传统的匿名内部类相当甚至更好。因此,我们无需过度担心 Lambda 表达式的性能问题,而应该侧重于在代码的可读性、可维护性和可重复使用性等方面进行考虑和优化。同时,在涉及到大量计算的场景时,可以采用其他方式,如并行处理等,来进一步优化 Lambda 表达式的性能。

八、结语

本文主要介绍了 Java 8 引入 Lambda 表达式的概念、语法和应用场景以及如何充分利用 Lambda 表达式来提高代码的效率和可读性。同时,我们也揭示了 Java 8 的新特性带来的性能提升。Lambda 表达式已经成为 Java 开发中不可或缺的技术特性之一。


http://lihuaxi.xjx100.cn/news/1133169.html

相关文章

怎样实现RPC框架

随着微服务架构的盛行&#xff0c;远程调用成了开发微服务必不可少的能力&#xff0c;RPC 框架作为微服务体系的底层支撑&#xff0c;也成了日常开发的必备工具。当下&#xff0c;RPC 框架已经不仅是进行远程调用的基础工具&#xff0c;还需要提供路由、服务发现、负载均衡、容…

九耶丨阁瑞钛伦特-springboot(一)

Spring Boot是一种基于Spring框架的快速应用开发框架。相比于传统的Spring框架&#xff0c;Spring Boot具有更加简洁明了的配置方式&#xff0c;可以帮助开发者快速搭建和部署项目&#xff0c;提高开发效率。 在工程技术领域&#xff0c;快速响应市场需求是企业发展的关键。传…

计算机网络 | 五种I/O模型

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

什么是独享数据库(Database per Microservice)?解决了什么问题?

独享数据库&#xff08;Database per Microservice&#xff09;是一种微服务架构模式&#xff0c;涉及为每个微服务创建单独的数据库。在这种模式下&#xff0c;每个微服务都有自己的数据库&#xff0c;这允许更大的可扩展性、灵活性和自治性。 使用这种模式&#xff0c;每个微…

[day28]算法训练

房屋偷盗 解题思路 动态规划&#xff0c;创建一个数组dp&#xff0c;dp[i]表示偷到第i家时最大的金额&#xff0c;由于偷到相邻两家时&#xff0c;报警器会进行报警&#xff0c;所以有对于dp[i]有两种可能&#xff1a;第一种不偷第i家&#xff0c;则结果为dp[i-1],第二种偷第…

设计模式-职责链模式

职责链模式 文章目录 职责链模式什么是职责链模式为什么要用职责链模式如何使用职责链模式总结 什么是职责链模式 将请求的发送和接收解耦&#xff0c;让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链&#xff0c;并沿着这条链传递这个请求&#xff0c;直到链上…

定风波、渡重山、至未来:2023中国数字能源生态大会开启的新旅程

全球碳中和的时代背景下&#xff0c;面向3060发展目标&#xff0c;新使命、新技术、新应用的到来&#xff0c;都给能源产业带来了持续变革的必要性与可能性。 2023年5月11日&#xff0c;在2023中国数字能源生态大会上&#xff0c;华为数字能源技术有限公司总裁侯金龙发表了“融…

如何使用SVG.js库中的mask()和clip()方法创建这两种元素,以及它们的常见属性和用法

SVG.js是一款轻量级的JavaScript库&#xff0c;用于创建交互式的可缩放矢量图形&#xff08;SVG&#xff09;动画。在SVG.js中&#xff0c;mask和clipPath元素是非常有用的功能&#xff0c;能够将SVG图像切割、裁剪并添加效果。本文将为您介绍SVG.js中的mask和clipPath元素的相…