Lambda表达式常见用法
Lambda介绍
Lambda,别名函数式编程
函数式编程是一种编程范式。它把计算当成是数学函数的求值,从而避免改变状态和使用可变数据。它是一种声明式的编程范式,通过表达式和声明而不是语句来编程。
Lambda表达式的优缺点
优点:
- 代码简洁,开发迅速,方便函数式编程
- 非常容易进行并行计算,尤其适用于遍历结果,循环计算数值或者赋值时
- 结合 hashmap 的 computeIfAbsent 方法,递归运算非常快。java有针对递归的专门优化。
- 减少匿名内部类的创建,节省资源(匿名内部类会产生一个class文件,而Lambda不会产生class文件,所以在类加载时,Lambda表达式的效率更高。)
缺点:
- 代码可读性变差,不容易进行调试
- 不易于后期维护,必须熟悉lambda表达式和抽象函数中参数的类型
- 不能再foreach中修改forEach外面的值,强制类型转换不方便(一定要搞清楚到底是 map 还是 mapToDouble 还是 mapToInt)
- 性能方面,如果不并行计算,很多计算未必有传统的for性能要高(并行计算有时需要预热才显示出效率优势)
使用场景:
- 集合操作:Lambda表达式可以方便地对集合进行筛选、转换和聚合等操作。
- 接口的实现:当需要实现一个只有一个抽象方法的接口时,可以使用lambda表达式代替匿名内部类。
- 并行处理:使用Stream API和lambda表达式可以方便地进行并行处理,提高性能。
符号表示
lambda是一个匿名函数
() 里的表示参数
// 括号中的参数只有一个,()可以省略
// 括号中的参数列表的数据类型,可以省略不写(编译器自己会根据上下文语境推断出类型的)
{} 里的表示方法体
// Lambda体只有一句语句({ 只有一句语句 }),无论是否有返回值,都可以省略({ }, return , 分号 )
// 注意:在省略{ }的同时要(return)和分号一起省略
-> 表示lambda运算符
并行处理
什么是并行流?
就是利用多核 CPU 的计算能力来加速流式处理。当一个流进行并行处理时,数据会被分成多个部分,这些部分会同时在多个线程上处理,最后将部分结果合并起来得到最终结果。
我们可以通过调用 Collection 的 parallelStream() 或 Stream 的 parallel() 方法来获取一个并行流。
代码示例
public class Test {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
Stream<Integer> parallelStream = list.parallelStream();
// forEach – 并行执行
list.parallelStream().forEach(e -> doSomething(e));
// filter – 并行过滤
list.parallelStream().filter(e -> e > 2).forEach(e -> doSomething(e));
// map – 并行映射
list.parallelStream().map(e -> e * 2).forEach(e -> doSomething(e));
// reduce – 并行归约
Integer sum = list.parallelStream().reduce(0, (a, b) -> a + b);
// sorted – 并行排序
list.parallelStream().sorted().forEach(e -> doSomething(e));
}
}
通过并行流可以让许多常见的流操作利用多核 CPU 进行并行计算,从而获得更高的性能。但是,并不意味着所有的流操作都适合并行化,如果流处理的程序本身不是 CPU 密集型的,那么并行化可能得不到太大的性能提升,甚至有所下降。
简单运用示例
匿名内部类调用
函数式接口:只有一个方法的接口。只要是函数式接口,都可以通过匿名函数来实现。
public class Test {
interface Demo{
int method(String s);
}
public static void main(String[] args) {
// 匿名内部类调用
Demo demo = new Demo() {
@Override
public int method(String s) {
return Integer.parseInt(s);
}
};
int v = demo.method("111");
// lambda表达式
Demo demo2 = (s) -> {
return Integer.parseInt(s);
};
int v2 = demo2.method("222");
// 单行简写
Demo demo3 = s -> Integer.parseInt(s);
int v3 = demo3.method("333");
}
}
并行计算求和
public class Demo {
public static void main(String[] args) {
List<String> values = Arrays.asList("1","2","3","4");
System.out.println(sum(values));
}
public static int sum(List<String> values){
// mapToInt方法返回的是一个int的Stream,再次调用stream.sum()得到和
return values.parallelStream().mapToInt(i -> Integer.parseInt(i)).sum();
}
}
ArryList排序
public class Test1 {
public static void main(String[] args) {
/**
* 需求:
* 已知在ArryList中有若干个Person类对象,将这些Person对象按照年龄来降序排序
*/
List<Person> list = new ArrayList<>();
list.add(new Person("小蓝",10));
list.add(new Person("小红",11));
list.add(new Person("小紫",18));
list.add(new Person("小橙",20));
//在sort方法中,o1是最后面的元素,o2是倒数第二个元素,以此类推,流是处理元素是从后面开始取值。
list.sort((o1,o2) -> o2.age - o1.age);
}
}
TreeSet排序
public class Test2 {
public static void main(String[] args) {
// 使用Lambda表达式来实现Comparator接口,并实例化一个TreeSet对象
TreeSet<Person> set = new TreeSet<>((o1,o2) -> {
if(o1.age >= o2.age){
return -1;
}else {
return 1;
}
});
set.add(new Person("小蓝",10));
set.add(new Person("小红",11));
set.add(new Person("小紫",18));
set.add(new Person("小橙",20));
System.out.println(set);
}
}
forEach遍历输出
public class Test3 {
public static void main(String[] args) {
//集合的遍历
ArrayList<Integer> list = new ArrayList<>();
//添加元素
Collections.addAll(list,1,2,3,4,5,6,7,8,9);
for (Integer integer : list) {
System.out.println(integer);
}
//将集合中的每一个元素带入到方法accept中
list.forEach(System.out::println);
//还可以用forEach方法输出集合中的偶数
list.forEach(elm -> {
if(elm %2 == 0){
System.out.println(elm);
}
});
}
}
removeIf删除方法
public class Test4 {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("小蓝",10));
list.add(new Person("小红",11));
list.add(new Person("小紫",10));
list.add(new Person("小橙",20));
//之前删除年龄大于10岁的元素 使用迭代器删除
ListIterator<Person> it = list.listIterator();
while (it.hasNext()){
Person person = it.next();
if (person.age > 10){
it.remove();
}
}
//使用lambda实现
//将集合中的每一个元素都带入到test方法中,如果返回值是true将删除
list.removeIf(t -> {
if (t.age > 10){
return true;
}else {
return false;
}
});
//简化
list.removeIf(t -> t.age>10);
System.out.println(list);
}
}
开辟线程
public class Test5 {
public static void main(String[] args) {
//使用lambda表达式开辟一个线程,做一个数字的输出
Thread t = new Thread(() -> {
for (int i =0; i<10; i++){
System.out.println(i);
}
});
t.start();
}
}
Stream的使用
Stream流的filter使用
List<String> list = Arrays.asList("张三", "李四", "王五", "小六");
List<String> result = list.stream().filter(str -> !"李四".equals(str)).collect(Collectors.toList());
System.out.println("stream 过滤之后:" + result);
String result2 = list.stream().filter(str -> "李四".equals(str)).findAny().orElse("找不到!");
System.out.println("stream 过滤之后 2:" + result2);
Stream流的map使用
// 示例一:转换大写
List<String> list1 = Arrays.asList("zhangSan", "liSi", "wangWu");
List<String> list11 = list1.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println("转换之后的数据:" + list11);
// 示例二:转换数据类型
List<String> list2 = Arrays.asList("1", "2", "3");
List<Integer> list22 = list2.stream().map(Integer::valueOf).collect(Collectors.toList());
System.out.println("转换之后的数据:" + list22);
// 示例三:获取平方
List<Integer> list3 = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });
List<Integer> list33 = list3.stream().map(n -> n * n).collect(Collectors.toList());
System.out.println("平方的数据:" + list33);
// 示例四:list对象转list对象
// 将List<User>对象中的name属性转换为List<String>对象
List<String> listStr= user.stream().map(x -> x.getName()).collect(Collectors.toList());
// 将List<String>对象转换为List<User>对象
List<User> userList = listStr.stream().map(name-> {
User user= new User();
user.setName(name);
user.setPassword(null);
user.setAge(null);
return user;
}).collect(Collectors.toList());
// 简写
List<User> userList = listStr.stream().map(name-> new User(name)).collect(Collectors.toList());
// 将List<User>对象转换为List<UserInfo>对象
List<UserInfo> collect = userList.stream().map(l -> new UserInfo(l.getName(), l.getPassword())).collect(Collectors.toList());
Stream流的sort使用
List<String> list = Arrays.asList("张三", "李四", "王五", "小六");
list.stream().limit(3).sorted().forEach(System.out::println);
// 先排序后比较效率更高
List<User> listUser = new ArrayList<User>();
listUser.stream().limit(3).sorted((u1, u2) -> u1.getName().compareTo(u2.getName())).collect(Collectors.toList());
Stream流的max/min/distinct使用
// 示例一:取最大/最小值
List<String> list13 = Arrays.asList("zhangsan","lisi","wangwu","xuwujing");
int maxLines = list13.stream().mapToInt(String::length).max().getAsInt();
int minLines = list13.stream().mapToInt(String::length).min().getAsInt();
System.out.println("最长字符的长度:" + maxLines+",最短字符的长度:"+minLines);
// 示例二:得到去重之后的数据
String lines = "good good study day day up";
List<String> list14 = new ArrayList<String>();
list14.add(lines);
List<String> words = list14.stream().flatMap(line -> Stream.of(line.split(" "))).filter(word -> word.length() > 0).map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());
System.out.println("去重复之后:" + words);
Stream流的reduce使用
reduce 主要作用是把 Stream 元素组合起来进行操作。
// 示例一:字符串连接
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
System.out.println("字符串拼接:" + concat);
// 示例二:得到最小值
double minValue = Stream.of(-4.0, 1.0, 3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
System.out.println("最小值:" + minValue);
// 示例三:求和
// 求和, 无起始值
int sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
System.out.println("有无起始值求和:" + sumValue);
// 求和, 有起始值
sumValue = Stream.of(1, 2, 3, 4).reduce(1, Integer::sum);
System.out.println("有起始值求和:" + sumValue);
// 示例四:过滤拼接
concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
System.out.println("过滤和字符串连接:" + concat);
Stream流的Match使用
- allMatch:Stream 中全部元素符合则返回 true ;
- anyMatch:Stream 中只要有一个元素符合则返回 true;
- noneMatch:Stream 中没有一个元素符合则返回 true。
// 检查数据是否符合
boolean all = lists.stream().allMatch(u -> u.getId() > 3);
System.out.println("是否都大于3:" + all);
boolean any = lists.stream().anyMatch(u -> u.getId() > 3);
System.out.println("是否有一个大于3:" + any);
boolean none = lists.stream().noneMatch(u -> u.getId() > 3);
System.out.println("是否没有一个大于3的:" + none);
双冒号之方法引用
Integer::parseInt; // 方法引用
Integer::new; // 引入构造方法
interface Demo{
int method(String s);
}
public class TestTwo {
public static void main(String[] args) {
// 匿名内部类调用
Demo demo1 = new Demo() {
@Override
public int method(String s) {
return Integer.parseInt(s);
}
};
int v1 = demo1.method("111");
System.out.println(v1);
// Lambda表达式
Demo demo2 = s -> {
return Integer.parseInt(s);
};
int v2 = demo2.method("222");
System.out.println(v2);
// Lambda表达式 单行简写
Demo demo3 = s -> Integer.parseInt(s);
int v3 = demo3.method("333");
System.out.println(v3);
// 方法引用 双冒号::
Demo demo4 = Integer::parseInt;
int v4 = demo4.method("444");
System.out.println(v4);
// 引入构造方法
Demo demo5 = Integer::new;
int v5 = demo5.method("555");
System.out.println(v5);
// 排序示例
List<Integer> list = Arrays.asList(20, 53, 16, 95, 100);
// 方式一:匿名内部类
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
});
// 方式二:Lambda表达式
list.sort((x,y) -> Integer.compare(x,y));
// 方式三:静态方法引用
list.sort(Integer::compare);
// 打印
list.forEach(System.out::println);
}
}
Lambda表达式常见用法的更多相关文章
- python lambda表达式简单用法【转】
python lambda表达式简单用法 1.lambda是什么? 看个例子: g = lambda x:x+1 看一下执行的结果: g(1) >>>2 g(2) >>& ...
- C++11 中function和bind以及lambda 表达式的用法
关于std::function 的用法: 其实就可以理解成函数指针 1. 保存自由函数 void printA(int a) { cout<<a<<endl; } std:: ...
- Lambda 表达式递归用法实例
注意: 使用Lambda表达式会增加额外开销,但却有时候又蛮方便的. Windows下查找子孙窗口实例: HWND FindDescendantWindows(HWND hWndParent, LPC ...
- python lambda表达式简单用法
习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,即: 1 2 3 4 5 6 7 8 # 普通条件语句 if 1 == 1: name = 'wupeiqi' else ...
- 快速掌握Java中Lambda表达式的用法
Lambda表达式的作用: Lambda表达式的作用就是简化代码开发,让代码看起来更加简介.它是用来简化匿名内部类的.但是并不是所有的匿名内部类都能用Lambda表达式简化,Lambda表达式是有使用 ...
- lambda函数常见用法
# lambda 参数:返回值/表达式 # print((lambda :100)()) # f = lambda a,b : a + b # print(f(10, 20)) # f = lambd ...
- 第一章 EL表达式常见用法
el最常用的几种使用场景: 从配置文件中读取属性 缺失值情况下,配置默认值 el内部字符串使用String的方法 三目运算符 正则表达式 注入系统属性(system properties) 调用系统原 ...
- C++ Lambda表达式基本用法(言简意赅,非常清楚)
创建一个匿名函数并执行.Objective-C采用的是上尖号^,而C++ 11采用的是配对的方括号[].实例如下: 1 2 3 4 5 6 7 8 9 #include <iostream> ...
- Lambda表达式的用法
参考:https://www.cnblogs.com/knowledgesea/p/3163725.html
- c++中lambda表达式的用法
#include <iostream> using namespace std; int main(){ ; auto func1 = [=](;}; auto func2 = [& ...
随机推荐
- WebGL:使用着色器进行几何造型
前言 本文将介绍如何使用着色器来进行几何造型,说到几何图形大家一定都不陌生,比如说三角形.圆形,接触过WebGL基础使用的小伙伴一定都知道怎么去在画布上绘制一个三角形,只要传入三个顶点坐标,并选择绘图 ...
- 虚拟机上k8s部署好的第二天用时总是出现的各种问题
open /run/flannel/subnet.env: no such file or directory open /run/flannel/subnet.env: no such file o ...
- java的synchronized有几种加锁方式
在Java中,synchronized关键字提供了内置的支持来实现同步访问共享资源,以避免并发问题.synchronized主要有三种加锁方式: 1.同步实例方法 当一个实例方法被声明为synchro ...
- vue2.0,把vform666、workFlow开源组件集成到vue-admin-template框架上心得体会
以上三个都是vue2版本的开源项目,有的已经有vue3版本了,我把他们集成到一起,是出于练习的目的,也是消磨时间. vue-admin-template是一个很基础简洁的后台管理系统框架:vform6 ...
- C# XML转Json Json转XML XML 转对象 对象转XML
对象转XML对象时,只能是一个JObject对象,不能是一个集合对象.如果对象是一个列表集合,需要定义一个根对象比如这样:var obj =new { Root = ListLogs[ListLogs ...
- 二叉树的遍历(BFS、DFS)
二叉树的遍历(BFS.DFS) 本文分为以下部分: BFS(广度优先搜索) DFS(深度优先搜索) 先序遍历 中序遍历 后序遍历 总结 BFS(广度优先搜索) 广度优先搜索[^1](英语:Breadt ...
- WPF开发快速入门【8】WPF进行简单的3D开发
概述 本文介绍采用WPF进行3D开发的一些基础知识,还有HelixToolkit控件的介绍以及在MVVM模式下使用3D框架. 3D开发入门 官方文档对3D开发的一些基础知识已经描述的比较详细了:三维图 ...
- 【终极指南】使用Python可视化分析文本情感倾向
本文分享自华为云社区<Python理解文本情感倾向的终极指南>,作者: 柠檬味拥抱. 情感分析是一种通过自然语言处理技术来识别.提取和量化文本中的情感倾向的方法.Python在这一领域有着 ...
- 将编译过的C++库迅速部署在Visual Studio新项目中
本文介绍在Visual Studio中,通过属性表,使得一个新建解决方案中的项目可以快速配置已有解决方案的项目中各类已编译好的C++第三方库的方法. 例如,我们现有一个解决方案,其中的一个项目 ...
- MYSQL 移机重装步骤(windows11)
MYSQL 移机重装步骤(windows11) 目的:已有电脑 A,D盘安装有mysql(安装方式为免安装) , 准备在另一台电脑B上,复制安装电脑A上的mysql(8.0.23版本) . 要 ...