Java函数式编程(三):列表的转化

 更新时间:2014年09月25日 11:52:41   作者:deepinmind  
这篇文章主要介绍了Java函数式编程(二):列表的转化,lambda表达式不仅能帮助我们遍历集合,并且可以进行集合的转化,需要的朋友可以参考下

列表的转化

将集合转化成一个新的集合就和遍历它一样简单。假设我们要将列表中的名字转化成全大写的。我们看下都有哪些实现方式。

Java中的字符串是不可变的,所以它没法改变。我们可以生成新的字符串,用来替换列表中原有的元素。然而这样做的话,原来列表就没了;还有一个问题,原来的列表可能也是不可变的,比如Arrays.asList()生成的,所以修改原来的列表这招不行。还有一个缺点就是这样做很难并行操作。

生成一个新的全大写的列表是个不错的选择。

乍听起来这个建议弱爆了;性能是我们都很关注的一个问题。令人吃惊的是,函数式编程通常要比命令式的性能要高,我们在153页的性能问题中会讲到。

我们先开始用这个集合生成一个大写字母的新集合吧。

复制代码 代码如下:

final List<String> uppercaseNames = new ArrayList<String>();
for(String name : friends) {
uppercaseNames.add(name.toUpperCase());
}

在命令式的代码中,我们先创建一个空列表,然后把大写的名字填充进去,在遍历原来列表的过程中,每次插入一个。为了改进成函数式的版本,我们第一步可以考虑采用19页遍历列表中提到的那个内部迭代器forEach来替换一下for循环,正如下例所示的那样。
复制代码 代码如下:

final List<String> uppercaseNames = new ArrayList<String>();
friends.forEach(name -> uppercaseNames.add(name.toUpperCase()));
System.out.println(uppercaseNames);

我们用了内部迭代器,但还得新建一个列表,然后再把元素插入到里面。我们还可以进一步改进。

使用lambda表达式

一个新引入的Stream接口里面,有个map方法,它可以帮助我们远离可变性,并使代码看起来更简洁。Steam有点像集合的迭代器,同时它还提供了流函数(fluent functions)的功能。使用这个接口的方法,我们可以把一系列调用给组合起来,使代码读起来就像描述问题的顺序一样,可读性更强。

Steam的map方法可以用来将输入序列转化成一个输出的序列——这和我们要做的工作非常匹配。

复制代码 代码如下:

friends.stream()
.map(name -> name.toUpperCase())
.forEach(name -> System.out.print(name + " "));
System.out.println();

JDK8中的所有集合都支持这个stream方法,它把集合封装成一个Steam实例。map方法对Stream中的每个元素都调用了指定的lambda表达式或者代码块。map方法跟forEach方法很不一样, forEach只是简单的对集合中的元素执行了一下指定的函数。而map方法把lambda表达式的运行结果收齐起来,返回一个结果集。最后我们用forEach方法打印了所有的元素。

新集合中的名字全都是大写的了:

复制代码 代码如下:

BRIAN NATE NEAL RAJU SARA SCOTT

map方法很适合把一个输入集合转化成一个新的输出集合。这个方法确保了输入输出序列的元素的数量是相同的。然而输入元素和输出元素的类型可以是不一样的。在这个例子中,我们输入和输出的都是字符串的集合。我们可以传给map方法一段代码,让它返回比如说名字中包含字符的个数。这样的话,输入的还是字符串的序列,而输出的却是数字序列了,就像下面这样。

复制代码 代码如下:

friends.stream()
.map(name -> name.length())
.forEach(count -> System.out.print(count + " "));

结果是每个名字中字母的个数:
复制代码 代码如下:

5 4 4 4 4 5

使用了lambda表达式的之后版本,避免了显式的修改操作;这样的代码非常简洁。这样写不再需要初始化空的集合以及那个垃圾变量了;这个变量乖乖的躲到了底层实现里面了。

使用方法引用

我们还可以使用方法引用让它变得更简洁一些。在需要传入函数式接口的实现的地方,Java编译器可以接受lambda表达式或者是方法引用。有了这个特性,用String::toUpperCase就可以替换掉name -> name.toUpperCase()了,就像这样:

复制代码 代码如下:

friends.stream()
.map(String::toUpperCase)
.forEach(name -> System.out.println(name));

当参数传入到这个生成的方法——函数式接口的抽象方法的实现——里面的时候,Java会去调用这个String参数的toUpperCase方法。这个参数引用在这里就隐藏起来了。像前面这种简单的场景,我们可以用方法引用来替换掉lambda表达式;更多的内容看一下26页的什么时候应该使用方法引用。

复制代码 代码如下:

小伙伴发问了:
什么时候应该使用方法引用?

当使用Java编程的时候,通常我们用lambda表达式的时候要比方法引用多得多。但这并不意味着方法引用不重要或者没啥用处。当lambda表达式非常简短的时候,它是一个很好的替代方案,它直接调用了实例方法或者静态方法。也就是说,如果lambda表达式只是传递了一下参数给方法调用的话,我们应该改用方法引用。
像这样的lambda表达式,有点像Tom Smykowski在电影上班一条虫中讲的那样,它的工作就是"从客户那把需求拿给软件工程师"。因为这个,我把这种重构成方法引用的模式叫做上班一条虫模式。
除了简洁外,使用方法引用,方法名字本身的含义和作用可以更好的体现出来。
使用方法引用背后,编译器起到了很关键的作用。方法引用的目标对象和参数都会从这个生成的方法里传进来的参数那推导出来。这才使得你可以使用方法引用写出比使用lambda表达式更简洁的代码。不过,如果参数在传递给方法之前或者调用结果在返回之后要被修改的话,这种便利的写法我们就用不了了。

在前面这个例子中,方法引用是引用了一个实例方法。方法引用还可以引用一个静态方法以及接受传参的方法。后面我们会看到这样的例子。

lambda表达式能帮助我们遍历集合,并且进行集合的转化。就像下面我们即将看到的,它还能帮助我们快速的从集合中选取一个元素。

相关文章

  • java获取到heapdump文件后快速分析技巧

    java获取到heapdump文件后快速分析技巧

    大家都知道HeapDump文件是指定时刻的Java堆栈的快照,是一种镜像文件,今天通过本文给大家介绍java获取到heapdump文件后,如何快速分析,需要的朋友可以参考下
    2023-04-04
  • SpringBoot中使用RocketMQ的示例代码

    SpringBoot中使用RocketMQ的示例代码

    本文主要介绍SpringBoot中使用RocketMQ的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Mybatis-Plus将字段设置为null解决方法

    Mybatis-Plus将字段设置为null解决方法

    MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增 强不做改变,为简化开发、提高效率而生,下面这篇文章主要给大家介绍了关于Mybatis-Plus将字段设置为null的解决方法的相关资料,需要的朋友可以参考下
    2023-04-04
  • springMVC中@RequestParam和@RequestPart的区别

    springMVC中@RequestParam和@RequestPart的区别

    本文主要介绍了springMVC中@RequestParam和@RequestPart的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-06-06
  • Mybatis映射文件之常用标签及特殊字符的处理方法

    Mybatis映射文件之常用标签及特殊字符的处理方法

    这篇文章主要介绍了Mybatis映射文件常用标签及特殊字符的处理,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • java调用openoffice将office系列文档转换为PDF的示例方法

    java调用openoffice将office系列文档转换为PDF的示例方法

    本篇文章主要介绍了java使用openoffice将office系列文档转换为PDF的示例方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-11-11
  • Mybatis通过数据库表自动生成实体类和xml映射文件

    Mybatis通过数据库表自动生成实体类和xml映射文件

    这篇文章主要介绍了Mybatis通过数据库表自动生成实体类和xml映射文件的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Spring实现源码下载编译及导入IDEA过程图解

    Spring实现源码下载编译及导入IDEA过程图解

    这篇文章主要介绍了Spring实现源码下载编译及导入IDEA,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • Spring c3p0配置的实现示例

    Spring c3p0配置的实现示例

    在Spring框架中配置c3p0连接池可以提升数据库操作性能,本文主要介绍了Spring c3p0配置的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-09-09
  • 浅谈Java中的克隆close()和赋值引用的区别

    浅谈Java中的克隆close()和赋值引用的区别

    下面小编就为大家带来一篇浅谈Java中的克隆close()和赋值引用的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09

最新评论