java8 Lambda理解

深入理解Java 8的Streams和Lambda表达式 本文通过解析Java 8中Streams和Lambda表达式的实际用例,探讨了它们的工作原理和最佳实践。包括并行流的使用、函数式接口的对比、以及流操作的并发处理等关键知识点。 阅读详情

Lambda初体验

下面进入本文的正题–lambda表达式。首先我们看一下什么是lambda表达式。以下是维基百科上对于”Lambda expression”的解释:

 a function (or a subroutine) defined, and possibly called, without being bound to an identifier。

简单点说就是:一个不用被绑定到一个标识符上,并且可能被调用的函数。这个解释还不够通俗,lambda表达式可以这样定义(不精确,自己的理解):一段带有输入参数的可执行语句块。这样就比较好理解了吧?一例胜千言。有读者反馈:不理解Stream的含义,所以这里先提供一个没用stream的lambda表达式的例子。

1//这里省略list的构造
2List<String> names = ...;
3Collections.sort(names, (o1, o2) -> o1.compareTo(o2));

 

1//这里省略list的构造
2List<String> names = ...;
3Collections.sort(names, new Comparator<String>() {
4  @Override
5  public int compare(String o1, String o2) {
6    return o1.compareTo(o2);
7  }
8});

上面两段代码分别是:使用lambda表达式来排序和使用匿名内部类来排序。这个例子可以很明显的看出lambda表达式简化代码的效果。接下来展示lambda表达式和其好基友Stream的配合。

1List<String> names = new ArrayList<>();
2names.add("TaoBao");
3names.add("ZhiFuBao");
4List<String> lowercaseNames = names.stream().map((String name) -> {returnname.toLowerCase();}).collect(Collectors.toList());

这段代码就是对一个字符串的列表,把其中包含的每个字符串都转换成全小写的字符串(熟悉Groovy和Scala的同学肯定会感觉很亲切)。注意代码第四行的map方法调用,这里map方法就是接受了一个lambda表达式(其实是一个java.util.function.Function的实例,后面会介绍)。

为什么需要Lambda表达式呢?在尝试回答这个问题之前,我们先看看在Java8之前,如果我们想做上面代码的操作应该怎么办。

先看看普通青年的代码:

1List<String> names = new ArrayList<>();
2names.add("TaoBao");
3names.add("ZhiFuBao");
4List<String> lowercaseNames = new ArrayList<>();
5for (String name : names) {
6  lowercaseNames.add(name.toLowerCase());
7}

接下来看看文艺青年的代码(借助Guava):

1List<String> names = new ArrayList<>();
2names.add("TaoBao");
3names.add("ZhiFuBao");
4List<String> lowercaseNames = FluentIterable.from(names).transform(new Function<String, String>() {
5  @Override
6  public String apply(String name) {
7    return name.toLowerCase();
8  }
9}).toList();

在此,我们不再讨论普通青年和文艺青年的代码风格孰优孰劣(有兴趣的可以去google搜索“命令式编程vs声明式编程”)。本人更加喜欢声明式的编程风格,所以偏好文艺青年的写法。但是在文艺青年代码初看起来看起来干扰信息有点多,Function匿名类的构造语法稍稍有点冗长。所以Java8的lambda表达式给我们提供了创建SAM(Single Abstract Method)接口更加简单的语法糖。


Lambda语法详解

我们在此抽象一下lambda表达式的一般语法:

1(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
2  statment1;
3  statment2;
4  //.............
5  return statmentM;
6}

从lambda表达式的一般语法可以看出来,还是挺符合上面给出的非精确版本的定义–“一段带有输入参数的可执行语句块”。

上面的lambda表达式语法可以认为是最全的版本,写起来还是稍稍有些繁琐。别着急,下面陆续介绍一下lambda表达式的各种简化版:

1. 参数类型省略–绝大多数情况,编译器都可以从上下文环境中推断出lambda表达式的参数类型。这样lambda表达式就变成了:

1(param1,param2, ..., paramN) -> {
2  statment1;
3  statment2;
4  //.............
5  return statmentM;
6}

所以我们最开始的例子就变成了(省略了List的创建):

1List<String> lowercaseNames = names.stream().map((name) -> {returnname.toLowerCase();}).collect(Collectors.toList());

2. 当lambda表达式的参数个数只有一个,可以省略小括号。lambda表达式简写为:

1param1 -> {
2  statment1;
3  statment2;
4  //.............
5  return statmentM;
6}

所以最开始的例子再次简化为:

1List<String> lowercaseNames = names.stream().map(name -> {returnname.toLowerCase();}).collect(Collectors.toList());

3. 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号。lambda表达式简化为:

1param1 -> statment

所以最开始的例子再次简化为:

1List<String> lowercaseNames = names.stream().map(name -> name.toLowerCase()).collect(Collectors.toList());

4. 使用Method Reference(具体语法后面介绍)

1//注意,这段代码在Idea 13.0.2中显示有错误,但是可以正常运行
2List<String> lowercaseNames = names.stream().map(String::toLowerCase).collect(Collectors.toList());

Lambda表达式眼中的外部世界

我们前面所有的介绍,感觉上lambda表达式像一个闭关锁国的家伙,可以访问给它传递的参数,也能自己内部定义变量。但是却从来没看到其访问它外部的变量。是不是lambda表达式不能访问其外部变量?我们可以这样想:lambda表达式其实是快速创建SAM接口的语法糖,原先的SAM接口都可以访问接口外部变量,lambda表达式肯定也是可以(不但可以,在java8中还做了一个小小的升级,后面会介绍)。

1String[] array = {"a", "b", "c"};
2for(Integer i : Lists.newArrayList(1,2,3)){
3  Stream.of(array).map(item -> Strings.padEnd(item, i, '@')).forEach(System.out::println);
4}

上面的这个例子中,map中的lambda表达式访问外部变量Integer i。并且可以访问外部变量是lambda表达式的一个重要特性,这样我们可以看出来lambda表达式的三个重要组成部分:

  • 输入参数
  • 可执行语句
  • 存放外部变量的空间

不过lambda表达式访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)。

1String[] array = {"a", "b", "c"};
2for(int i = 1; i<4; i++){
3  Stream.of(array).map(item -> Strings.padEnd(item, i, '@')).forEach(System.out::println);
4}

上面的代码,会报编译错误。因为变量i被lambda表达式引用,所以编译器会隐式的把其当成final来处理(ps:大家可以想象问什么上一个例子不报错,而这个报错。)细心的读者肯定会发现不对啊,以前java的匿名内部类在访问外部变量的时候,外部变量必须用final修饰。Bingo,在java8对这个限制做了优化(前面说的小小优化),可以不用显示使用final修饰,但是编译器隐式当成final来处理。

lambda眼中的this

在lambda中,this不是指向lambda表达式产生的那个SAM对象,而是声明它的外部对象。

方法引用(Method reference)和构造器引用(construct reference)

方法引用

前面介绍lambda表达式简化的时候,已经看过方法引用的身影了。方法引用可以在某些条件成立的情况下,更加简化lambda表达式的声明。方法引用语法格式有以下三种:

  • objectName::instanceMethod
  • ClassName::staticMethod
  • ClassName::instanceMethod

前两种方式类似,等同于把lambda表达式的参数直接当成instanceMethod|staticMethod的参数来调用。比如System.out::println等同于x->System.out.println(x);Math::max等同于(x, y)->Math.max(x,y)。

最后一种方式,等同于把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。比如String::toLowerCase等同于x->x.toLowerCase()。

构造器引用

构造器引用语法如下:ClassName::new,把lambda表达式的参数当成ClassName构造器的参数 。例如BigDecimal::new等同于x->new BigDecimal(x)。

吐槽一下方法引用

表面上看起来方法引用和构造器引用进一步简化了lambda表达式的书写,但是个人觉得这方面没有Scala的下划线语法更加通用。比较才能看出,翠花,上代码!

1List<String> names = new ArrayList<>();
2names.add("TaoBao");
3names.add("ZhiFuBao");
4names.stream().map(name -> name.charAt(0)).collect(Collectors.toList());

上面的这段代码就是给定一个String类型的List,获取每个String的首字母,并将其组合成新的List。这段代码就没办法使用方法引用来简化。接下来,我们简单对比一下Scala的下划线语法(不必太纠结Scala的语法,这里只是做个对比):

1//省略List的初始化
2List[String] names = ....
3names.map(_.charAt(0))

在Scala中基本不用写lambda表达式的参数声明。

Modbus TCP 通信(C#) 【代码】Modbus TCP 通信(C#) 阅读详情

相关推荐

避坑指南:用逐飞开源库驱动MT9V03X摄像头时容易忽略的3个细节(附TFT显示优化技巧)

本文详细解析了在智能汽车竞赛中使用MT9V03X摄像头(总钻风)时常见的硬件连接、图像采集和TFT显示优化问题。重点介绍了逐飞开源库中容易被忽略的三个关键细节,包括电源管理、看门狗设置和中断优先级配置,并提供了针对IPS200和TFT180显示屏的优化技巧,帮助参赛队伍提升图像处理效率和显示质量。

study的专栏 742

Java 将List集合中的数据倒序、复制

如果想将List集合中的数据全部倒序又不重新new一个集合的话可以使用: List<String> list = new ArrayList(); list.add("a"); list.add("b"); list.add("c"); Collections.reverse(list); 这样本来是:a,b,c --> c,b,a 当然想要复制list集合中的数据也是有方法的,可以使用:List list1= Collections.copy(list) 以上就是将List集合中的数据

程序小白进阶之路 3793

Dual-stream multiple instance learning networks for tumor detection in Whole Slide Image——论文笔记

关于多示例学习的资料网上比较少,但是在医学图像方面还是有人在应用的。主要是因为一般比较大,几个G都是十分常见的,这么大图片是无法直接训练,一般都会进行切图,所以天然契合多示例学习bag和instance的概念。最近看了一篇论文刚好关于这方面的,所以做下笔记。 github地址:https://github.com/binli123/dsmil-wsi paper:https://arxiv.org/abs/2011.08939 背景知识 在多示例学习(MIL)中,一组训练样本被视为包含多个instance的

weixin_41693877的博客 4170

Java8初体验(一)lambda表达式语法

本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘。因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解偏差的地方,希望大家帮忙指出,我会持续修改和优化。本文是该系列的第一篇,主要介绍Java8对屌丝码农最有吸引力的一个特性—lambda表达式。 java8的安装 工欲善其器必先利其器,首先安装JDK8。过程省略,大家应该都可以自己搞定。但是有一点这里强调一下(Wind

楠人的博客-随风而过 1015

手把手教你用Multisim搭建FM直接调频电路(附完整波形分析)

本文通过Multisim仿真软件,手把手教你搭建FM直接调频电路。详细介绍了从核心概念理解、压控振荡器(VCO)参数设置、电路搭建与波形观测,到带通滤波器设计与信号优化的完整流程。通过对比滤波前后的时域波形与频谱分析,帮助读者直观理解频率调制原理,并提供了常见问题的排查思路与参数调试方法,将抽象的通信理论转化为可操作的实践技能。

weixin_29230773的博客 214

利用Pandas进行高效网络数据获取

本文将重点介绍如何使用Pandas库进行网络爬虫。爬取数据是获取互联网上信息的常见方式之一,而Pandas作为一种强大的数据处理和分析工具,为我们提供了便捷的方法来处理和清洗从网页上获取的数据。文章将从爬取网页数据开始,包括使用Python的Requests库发送HTTP请求获取网页内容,并使用Pandas的功能来解析和提取所需的数据。我们还将讨论如何处理网页中的表格数据、处理和清洗数据、保存数据到文件等常见任务。

ak_bingbing的博客 1437

关于list倒序的两个小方法

关于list倒序的两个小方法 转自:http://www.blogjava.net/jzone/articles/277672.html 第一个:commReverse 这个比较简单,一般都会想到 第二个:stackReverse 这个道理也很简单,利用堆栈原理。对对象进行进出栈操作,形成自然倒序 package com.yixun.wap; impo

GrimRaider的专栏 7477

把 SAP Fiori Launchpad Designer 的 Catalog 与 Group 传输讲透:从 CONF、CUST 到 Transport Request 的完整理解

SAP Fiori项目中,catalog和group的传输问题往往源于对FLPD层次模型的理解不足。FLPD包含configuration(系统级)和customizing(客户端级)两个层面,分别对应workbench request和customizing request传输方式。常见误区包括:混淆/UI2/FLPD_CONF和/UI2/FLPD_CUST入口、未提前创建传输请求、不了解层次覆盖机制(customizing会覆盖configuration)。当客户端修改configuration层的对象

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 98

lambda表达式

目录 1、为什么引入lambda表达式 2、lambda表达式形式 3、lambda表达式优缺点 4、lambda的应用示例 1、为什引入lambda表达式: lambda是一个可以传递的代码块,可以在以后执行一次或多次。lambda表达式允许把函数作为一个方法的参数(函数作为参数传递进方法中) 2、lambda表达式形式 一般形式为:参数,箭头(->)以及一...

Juliussss 757

VTK 显示大量点云数据及交互(点云拾取、着色、测量等)功能

VTK (Visualization Toolkit) 是一个强大的开源可视化库,非常适合处理点云数据。下面将介绍如何使用 VTK 显示大量点云数据,并实现点云拾取、着色、测量等功能。

深之JohnChen的专栏 1992

如何通过插值法计算cell delay?

插值法的公式:Z = A + B * X + C * Y + D * X * Y,其中X为input transition,Y为output load,A、B、C、D为四个参数,Z为delay值。从而得到Z=-0.086176 + 11.5493 * x + 0.65917 * y - 24.859 * x * y,当X=0.014930、Y=0.296311时,得到Z=0.1716ns。从而得到A = 0.08075,B = 3.47539,C = 0.04008,D = 0.01648。

芯冰乐 1075

Java中List通过Lambda实现排序正序、倒序

1. 正序: 1,2,3,4,5 list.stream().sorted(Comparator.comparing(Dto::getStateCode)).collect(Collectors.toList()); 2.降序: 5,4,3,2,1 .reversed() list.stream().sorted(Comparator.comparing(Dto::getStateCode).reversed()).collect(Collectors.toList()); ...

封神之路 6143

【重识云原生】第四章云网络4.9.5.1节下一代智能网卡——DPU综述

随着数据中心的高速发展,通信能力和计算能力成为数据中心基础设施的相辅相成的两个重要发展方向。若数据中心仅关注计算能力的提升,通信基础设施的提升跟不上,那么数据中心的整体系统性能依然受限,无法发挥出真正的潜力。DPU的提出背景就是应对这些数据量和复杂性的指数级增长。未来,需要将计算移至接近数据的位置,这是目前业界所公认的以数据为中心的体系结构下的创新。综上,DPU对数据中心来说,是通过更明细的分工来实现效率的提升、实现总体系统的成本最优化。...

junbaozi的专栏 1724

【JAVA8】对Lambda的理解

对Lambda的理解 一、前言 从毕业起,接触lambda也有了4个多月了,期间也写过不少lambda表达式,今天就来梳理一下我对lambda理解的过程。 二、我不要你觉得,我要我觉得 网上讲的lambda概念太过生涩,不易理解,下面我谈谈自己的想法。 java中最简单的...

阳阳的博客 5642

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

深入理解Java 8 Lambda

作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://lucida.me/blog/java-8-lambdas-insideout-language-features/ 关于 深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法) 深入理解Java 8 Lambda(类库篇——S

isunn的专栏 2473

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

深入理解Java 8 Lambda-语言篇

最近在github.io上发现一篇讲解java8 lambda非常好的文章,但是最近这个文章的页面服务地址不稳定,所以转载下来,如果造成原作者的不满和任何的反对,请告知,我立即处理 原文地址:http://lucida.me/blog/java-8-lambdas-insideout-language-features/#more 深入理解Java 8 Lambda(语

没有伞的孩子只能快跑,如若不跑,只有一个结果:超过你的人回头鄙视你 1625

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

最近看了一下java 8的一些新特性,其中最重要的莫过于Lambda表达式了,通过一阵子的学习,原本准备自己写一篇博客的,后来阅读了一位学长翻译过来的博客(原文是Brain Goetz的State of Lambda,下面会给出原文链接),觉得写的十分完美,把我想要写的和我没想到的都罗列了出来,就把这个分享给大家了。 注:原译文见  http://lucida.me/blog/java-8-la

CallRock的博客 1408

理解Java 8 Lambda

前言为什么要写(翻译)本文? 工作之后,我开始大量使用Java 公司将会在不久的未来使用Java 8 作为资质平庸的开发者,我需要打一点提前量,以免到时拙计 为了学习Java 8(主要是其中的lambda及相关库),我先后阅读了Oracle的官方文档,Cay Horstmann(Core Java的作者)的Java 8 for the Really Impatient和Richard Warburt

狮子座明仔知识集散场 1063

深入理解 Java 8 Lambda

深入理解 Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)深入理解 Java 8 Lambda(类库篇——Streams API,Collector 和并行)深入理解 Java 8 Lambda(原理篇——Java 编译器如何处理 lambda)本文是深入理解 Java 8 Lambda 系列的第一篇,主要介绍 Java 8 新增的语言特性(比如 lambda 和...

quliuwuyiz的博客 1582

理解并运用Java8中的Lambda

前提回想一下,JDK8是2014年发布正式版的,到现在为(2020-02-08)止已经过去了5年多。JDK8引入的两个比较强大的新特性是Lambda表达式(下文的Lambda特指JDK提...

Java笔记虾 545

JAVA8中的Lambda理解使用

1.lambda表达式Java8最值得学习的特性就是Lambda表达式和Stream API,如果有python或者javascript的语言基础,对理解Lambda表达式有很大帮助,因为Java正在将自己变的更高(Sha)级(Gua),更人性化。--------可以这么说lambda表达式其实就是实现SAM接口的语法糖。lambda写的好可以极大的减少代码冗余,同时可读性也好过冗长的内部类,匿名...

瘦子没有夏天 2730
上一篇: lombok的使用和原理
下一篇: java8 stream理解(2)
shadow_zed
博客等级 码龄10年 6289粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值