lamda获取参数集合去空_(转)Java8使用lambda表达式进行集合的遍历

本文转自

我们经常会用到各种集合,数字的,字符串的还有对象的。它们无处不在,哪怕操作集合的代码要能稍微优化一点,都能让代码清晰很多。在这章中,我们探索下如何使用lambda表达式来操作集合。我们用它来遍历集合,把集合转化成新的集合,从集合中删除元素,把集合进行合并。

遍历列表

遍历列表是最基本的一个集合操作,这么多年来,它的操作也发生了一些变化。我们使用一个遍历名字的小例子,从最古老的版本介绍到现在最优雅的版本。

用下面的代码我们很容易创建一个不可变的名字的列表:

final List friends =

Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");

System.out.println(friends.get(i));

}

下面这是最常见的一种遍历列表并打印的方法,虽然也最一般:

for(int i = 0; i < friends.size(); i++) {

System.out.println(friends.get(i));

}

我把这种方式叫做自虐型写法——又啰嗦又容易出错。我们得停下来好好想想,"是i

Java还提供了一种相对先进的for结构。

collections/fpij/Iteration.java

for(String name : friends) {

System.out.println(name);

}

在底层,这种方式的迭代是使用Iterator接口来实现的,调用了它的hasNext和next方法。 这两种方式都属于外部迭代器,它们把如何做和想做什么揉到了一起。我们显式的控制迭代,告诉它从哪开始到哪结束;第二个版本则在底层通过Iterator的方法来做这些。显式的操作下,还可以用break和continue语句来控制迭代。 第二个版本比第一个少了点东西。如果我们不打算修改集合的某个元素的话,它的方式比第一个要好。不过这两种方式都是命令式的,在现在的Java中应该摒弃这种方式。 改成函数式原因有这几个:

for循环本身是串行的,很难进行并行化。

这样的循环是非多态的;所得即所求。我们直接把集合传给for循环,而不是在集合上调用一个方法(支持多态)来执行特定的操作。

从设计层面来说,这样 写的代码违反了“Tell,Don't Ask”的原则 。我们请求执行一次迭代,而不是把迭代留给底层库来执行。

是时候从老的命令式编程转换到更优雅的内部迭代器的函数式编程了。使用内部迭代器后我们把很多具体操作都扔给了底层方法库来执行,你可以更专注于具体的业务需求。底层的函数会负责进行迭代的。我们先用一个内部迭代器来枚举一下名字列表。

Iterable接口在JDK8中得到加强,它有一个专门的名字叫forEach,它接收一个Comsumer类型的参数。如名字所说,Consumer的实例正是通过它的accept方法消费传递给它的对象的。我们用一个很熟悉的匿名内部类的语法来使用下这个forEach方法:

friends.forEach(new Consumer() { public void accept(final String name) {

System.out.println(name); }

});

我们调用了friends集合上的forEach方法,给它传递了一个Consumer的匿名实现。这个forEach方法从对集合中的每一个元素调用传入的Consumer的accept方法,让它来处理这个元素。在这个示例中我们只是打印了一下它的值,也就是这个名字。 我们来看下这个版本的输出结果,和上两个的结果 是一样的:

Brian

Nate

Neal

Raju

Sara

Scott

我们只改了一个地方:我们抛弃了过时的 for循环,使用了新的内部迭代器。好处是,我们不用指定如何迭代这个集合,可以更专注于如何处理每一个元素。缺点是,代码看起来更啰嗦了——这简直要把新的编码风格带来的喜悦冲的一干二净了。所幸的是,这个很容易改掉,这正是lambda表达式和新的编译器的威力大展身手的时候了。我们再做一点修改,把匿名内部类换成lambda表达式。

friends.forEach((final String name) -> System.out.println(name));

这样看起来就好多了。代码更少了,不过我们先来看下这是什么意思。这个forEach方法是一个高阶函数,它接收一个lambda表达式或者代码块,来对列表中的元素进行操作。在每次调用的时候 ,集合中的元素会绑定到name这个变量上。底层库托管了lambda表达式调用的活。它可以决定延迟表达式的执行,如果合适的话还可以进行并行计算。 这个版本的输出也和前面的一样。

Brian

Nate

Neal

Raju

Sara

Scott

内部迭代器的版本更为简洁。而且,使用它的话我们可以更专注每个元素的处理操作,而不是怎么去遍历——这可是声明式的。

不过这个版本还有缺陷。一旦forEach方法开始执行了,不像别的两个版本,我们没法跳出这个迭代。(当然有别的方法能搞定这个)。因此,这种写法在需要对集合里的每个元素处理的时候比较常用。后面我们会介绍到一些别的函数可以让我们控制循环的过程。

lambda表达式的标准语法,是把参数放到()里面,提供类型信息并使用逗号分隔参数。Java编译器为了解放我们,还能自动进行类型推导。不写类型当然更方便了,工作少了,世界也清静了。下面是上一个版本去掉了参数类型之后的:

friends.forEach((name) -> System.out.println(name));

在这个例子里,Java编译器通过上下文分析,知道name的类型是String。它查看被调用方法forEach的签名,然后分析参数里的这个函数式接口。接着它会分析这个接口里的抽象方法,查看参数的个数及类型。即便这个lambda表达式接收多个参数,我们也一样能进行类型推导,不过这样的话所有参数都不能带参数类型;在lambda表达式中,参数类型要么全不写,要写的话就得全写。

Java编译器对单个参数的lambda表达式会进行特殊处理:如果你想进行类型推导的话,参数两边的括号可以省略掉。

friends.forEach(name -> System.out.println(name));

这里有一点小警告:进行类型推导的参数不是final类型的。在前面显式声明类型例子中,我们同时也把参数标记为final的。这样能防止你在lambda表达式中修改参数的值。通常来说,修改参数的值是个坏习惯,这样容易引起BUG,因此标记成final是个好习惯。不幸的是,如果我们想使用类型推导的话,我们就得自己遵守规则不要修改参数,因为编译器可不再为我们保驾护航了。

走到这步可费了老劲了,现在代码量确实少了一点。不过这还不算最简。我们来体验下最后这个极简版的。

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

在上面的代码中我们用到了一个方法引用。我们用方法名就可以直接替换整个的代码了。在下节中我们会深入探讨下这个,不过现在我们先来回忆下Antoine de Saint-Exupéry的一句名言:完美不是无法再增添加什么,而是无法再去掉什么。

lambda表达式让我们能够简洁明了的进行集合的遍历。下一节我们会讲到它如何使我们在进行删除操作和集合转化的时候,也能够写出如此简洁的代码。

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

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

相关文章

git@github.com:Permission denied(publickey).fatal: Could not read form remote repository错误

文章目录前言问题分析解决方法配置客户端配置服务端验证前言 在使用goland从github下载依赖时(git clone github.com/gin-gonic/gin)出现gitgithub.com:Permission denied(publickey).fatal: Could not read form remote repository错误。 问题分析 Permission denied(publi…

go出现missing go.sum entry for module providing package 错误

文章目录前言问题分析解决方法前言 从github下载了别人的代码后直接执行&#xff0c;报missing go.sum entry for module providing package错误 问题分析 代码中使用了第三方库&#xff0c;但是go.mod并没有跟着更新 解决方法 在项目目录下打开终端&#xff0c;执行go mo…

的计时器设置_如何选择最适合自己的计时器?

本文作者是Ultraman&#xff0c;他为了找到最适合自己的计时方法&#xff0c;试验了十多种计时器或者沙漏&#xff0c;总结出了非常棒的经验&#xff01;相信本文一定会对你有所帮助。 ——李长太大家对番茄工作法一定已经不陌生了&#xff0c;那么进行番茄工作法的时候&#x…

npm install报错 npm ERR,code ERESOLVE npm ERR,ERESOLVE unable to resolve dependency tree

文章目录前言问题分析解决方法转载于前言 在下载npm时报错npm ERR! code ERESOLVE npm ERR! ERESOLEVE unable to resolve dependency tree 问题分析 我的npm版本为8.x&#xff0c;npm6.x之后的版本更加严格了&#xff0c;所以会报错 解决方法 方法1&#xff0c;降级到np…

go的time.Time格式相关转换

文章目录time.Time 转 字符串time.Time 转 时间戳时间戳 转 time.Time时间戳 转 日期字符串日期字符串 转 time日期字符串 转 时间戳其他日期字符串yyyy-MM-dd转换为日期字符串yyyyMMddtime.Time 转 字符串 t.Format("2010-12-06") t.Format("2010-12-06 12:01…

go TypeError: Failed to execute ‘fetch‘ on ‘Window‘: Request with GET/HEAD method cannot have body.

文章目录前言问题分析解决方法前言 使用swagger测试一个Get路由时&#xff0c;想要传入form-data数据时报错TypeError: Failed to execute ‘fetch‘ on ‘Window‘: Request with GET/HEAD method cannot have body. 问题分析 GET把参数包含在URL中 POST把通过request body…

卡顿严重_微软Win 10游戏模式致《使命召唤:战区》等游戏出现严重卡顿现象

IT之家5月8日消息 据Windowslatest报道&#xff0c;有部分用户报告称Windows 10游戏模式可能对某些硬件的游戏性能产生负面影响。一位用户表示&#xff0c;启用游戏模式后&#xff0c;搭载Radeon RX 5700 XT、RX 480、R9 290等AMD显卡设备以及GTX 980和GTX 1080 Ti等Nvidia显卡…

gin的Bindxxx和ShouldBindxxx的区别

区别 Bindxxx&#xff1a;解析错误会在head中添加400的返回信息 ShouldBindxxx&#xff1a;解析错误直接返回&#xff0c;返回什么错误状态码由自己决定。

非知识类资源分享

文章目录好用的电脑软件好用的电脑软件 Quicker&#xff1a;windows上的一个工具箱软件&#xff0c;内置了电脑常用操作&#xff0c;一键完成需要多个步骤的工作。还可以通过Quicker的动作库安装别人分享的动作。推荐Smart Var码农的变量名动作&#xff0c;可以将中文直接转换…

MySQL的MVCC是什么

文章目录MVCC是什么MVCC的作用MVCC的实现原理Read View是什么Read View如何判断某个版本可以访问MVCC是什么 MVCC(Multiversion concurrency control)是同一行数据保留多版本的一种方式&#xff0c;进而实现并发控制。 在查询时&#xff0c;通过read view和版本链找到对应版本…

go中make、new和直接var的区别

文章目录直接varmakenew小结直接var func main(){var sli []intfmt.Println(sli) // 打印结果为&#xff1a;[]fmt.Println(len(sli)) // 打印结果为&#xff1a;0fmt.Println(cap(sli)) // 打印结果为&#xff1a;0fmt.Println(sli[0]) // panic: index out of…

[Redis] Redis穿透、雪崩和击穿

穿透 定义&#xff1a; 穿透是指请求的数据在Redis缓存中和数据库中都没有&#xff0c;所以数据库返回了一个空数据&#xff0c;Redis也不会进行缓存&#xff0c;每次请求的数据都会查询数据库。 解决方法&#xff1a; Redis对数据库返回的空数据也进行缓存&#xff0c;并设置…

[Redis] Redis几种部署方式

单机 优点&#xff1a; 部署简单 缺点&#xff1a; 性能受限于单台服务器性能&#xff0c;难以横向拓展&#xff0c;容灾能力差 主从同步 是什么&#xff1a; 主从同步即一个master节点&#xff0c;多个slave节点且slave节点也可拥有slave节点 主从同步的方式有两种&#xff…

论述类文本知识框架_高考语文“论述类文本阅读”:三步走,拿满分

【原创首发】新的学期开始了。高三的定位考试也结束了。成绩下来了&#xff0c;有的同学拿着卷子找着我&#xff1a;“老师&#xff0c;你看看&#xff0c;我第一道大题三道错了两道&#xff0c;咋办呀&#xff1f;”高考语文试卷的第一大道试题”论述类文本阅读“这道题&#…

mysql php ajax_PHP 和 AJAX MySQL 数据库实例

HTML 表单上面的例子包含了一个简单的 HTML 表单&#xff0c;以及指向 JavaScript 的链接&#xff1a;Select a User:Peter GriffinLois GriffinGlenn QuagmireJoseph SwansonUser info will be listed here.例子解释 - HTML 表单正如融金汇银讲到的&#xff0c;它仅仅是一个简…

mysql 5.1升级5.6_mysql 5.1.71升级到5.6.30

mysql 5.1.71升级到5.6.30mysqldump-h主机名 -P端口 -u用户名 -p密码 (–database) 数据库名 >文件名.sql备份MySQL数据库的命令mysqldump-hhostname -uusername -ppassword databasename >backupfile.sql备份MySQL数据库为带删除表的格式&#xff0c;能够让该备份覆盖已…

mysql时间段以后_mysql时间段查询

字段column_time的格式为时间格式from_unixtime将时间戳转换为时间格式 *做个记号&#xff0c;之前纠结了半天select * from wap_content where week(column_time) week(now)如果你要严格要求是某一年的&#xff0c;那可以这样查询一天&#xff1a;select * from table where …

mysql数据自定义随机_Mysql 自定义随机字符串

前几天在开发一个系统&#xff0c;需要用到随机字符串&#xff0c;但是mysql的库函数有没有直接提供&#xff0c;就简单的利用现有的函数东拼西凑出随机字符串来.下面简单的说下实现当时.1.简单粗暴.select ..., substring(MD5(RAND()),floor(RAND()*26)1,6) as rand_str .....…

php连接mysql乱码原因_PHP连接MYSQL出现乱码的原因与解决办法

PHP连接mysql出现乱码的原因与解决方法解决MySql数据库乱码的一个首要前提是保证 数据库数据表前端显示 编码一致&#xff0c;国内项目一般统一设定为GB2312或GBK&#xff0c;而国际化项目则一般使用utf8。另外&#xff0c;字符集设定完毕之后记得重启目标机MySql服务。PHP连接…

MYSQL数据库实验三多表查询_数据库之 MySQL --- 数据处理 之多表查询 (三)

一、多表查询【1】什么是多表查询&#xff1f;即&#xff0c;从多个表中获取数据。注意&#xff1a; 在多表查询是&#xff0c;如果列明在两个表中都有&#xff0c;那么列名前需要加上表名sql优化&#xff1a;列名前最好加上表名&#xff0c;尤其在多表查询时SELECT employees.…