`
deepinmind
  • 浏览: 452203 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:41679
社区版块
存档分类
最新评论

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

阅读更多
本系列文章译自Venkat Subramaniam的Functional Programming in Java

列表的转化

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

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页的什么时候应该使用方法引用


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

当使用Java编程的时候,通常我们用lambda表达式的时候要比方法引用多得多。但这并不意味着方法引用不重要或者没啥用处。当lambda表达式非常简短的时候,它是一个很好的替代方案,它直接调用了实例方法或者静态方法。也就是说,如果lambda表达式只是传递了一下参数给方法调用的话,我们应该改用方法引用。
<br>

像这样的lambda表达式,有点像Tom Smykowski在电影上班一条虫中讲的那样,它的工作就是"从客户那把需求拿给软件工程师"。因为这个,我把这种重构成方法引用的模式叫做上班一条虫模式。
<br>

除了简洁外,使用方法引用,方法名字本身的含义和作用可以更好的体现出来。
<br>

使用方法引用背后,编译器起到了很关键的作用。方法引用的目标对象和参数都会从这个生成的方法里传进来的参数那推导出来。这才使得你可以使用方法引用写出比使用lambda表达式更简洁的代码。不过,如果参数在传递给方法之前或者调用结果在返回之后要被修改的话,这种便利的写法我们就用不了了。

</blockquote>

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



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


未完待续,后续文章请继续关注deepinmind


原创文章转载请注明出处:http://it.deepinmind.com







3
6
分享到:
评论

相关推荐

    Scala函数式编程

    函数式编程(FP)是一种软件开发风格,它注重不依赖于编程状态的函数。函数式代码易于测试和复用,容易实现并发,且不容易受到bug的攻击。Scala是一种能很好支持函数式编程的新兴JVM语言。《Scala函数式编程》是针对...

    javascript函数式编程

    对于已经熟悉Java的开发者来说,学习JavaScript函数式编程不仅可以拓宽视野,也有助于提升在前端开发领域的专业技能。阅读相关书籍,例如"javascript函数式编程",将帮助你更好地掌握这些概念并应用于实际项目中。

    Java8 函数式编程1

    【Java 8 函数式编程】是针对Java开发者的一本技术书籍,主要讲解了Java 8引入的新特性,特别是函数式编程的概念及其应用。作者Richard Warburton旨在打破函数式编程仅限于少数人的认知,让更多的Java程序员能够理解...

    Java 8函数式编程1

    【Java 8函数式编程】 Java 8 是Java平台的一个重大更新,引入了多项新特性,其中最引人注目的就是对函数式编程的支持。函数式编程是一种编程范式,它强调程序的数据处理过程如同数学函数般进行,避免了副作用和可...

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

    在Java函数式编程中,列表的转化是一个关键概念,它允许我们通过操作集合来转换其元素,从而生成新的集合。在本节中,我们将深入探讨如何利用Lambda表达式和Java 8中的Stream API来实现这一目标。 首先,列表的转化...

    函数与函数式编程

    函数式编程语言包括Haskell、Lisp、Erlang、Scala、F#等,但即使在非函数式语言如Python、Java或C#中,也可以采用函数式编程风格。这种编程风格的一个关键概念是高阶函数,即可以接受其他函数作为参数或返回函数的...

    java8函数式编程学习源码

    Java 8 是一个重要的 Java 发布版本,引入了许多新特性,极大地改变了 Java 开发的方式,尤其是函数式编程的引入。本资源"java8函数式编程学习源码"显然是为了帮助开发者深入理解并实践这些概念。下面我们将详细探讨...

    函数式编程-haskell-to-java

    ### 函数式编程:Haskell到Java的转换 #### 概述 本文旨在探讨函数式编程语言Haskell如何被编译或转换为Java语言。Haskell作为一种纯函数式编程语言,以其强大的类型系统、惰性求值机制以及高度抽象的能力在学术界...

    jdk8函数式编程学习和复习必备

    【函数式编程与Java 8 Lambda表达式】 函数式编程是一种编程范式,它强调将计算过程视为函数的组合,而不是指令的序列。在Java 8中,引入了Lambda表达式,使得函数式编程思想得以在Java平台上实现,极大地提高了...

    Java函数式编程(八):字符串及方法引用

    Java函数式编程是一种编程范式,它强调使用函数作为程序的基本构建块,使得代码更加简洁、可读性强且易于测试。在Java 8及其后续版本中,函数式编程得到了广泛支持,引入了lambda表达式、函数式接口以及一系列用于...

    java优秀源码-fpij:源代码与优秀的书籍“Java中的函数式编程”紧密相关

    【标题】"java优秀源码-fpij"指的是一个与Java中的函数式编程...通过研究这个开源项目,不仅可以深化对Java函数式编程的理解,还能了解到实际项目中如何将理论知识转化为实践,提升自己的编程技能和解决问题的能力。

    简单了解java函数式编码结构及优势

    Java 函数式编程是一种编程范式,它强调使用函数作为一等公民,即函数可以作为变量赋值、作为参数传递和作为返回值。这种编程风格鼓励避免可变状态,提高代码的可读性和可维护性。函数式编程在Java中的应用通常通过...

    Javaz:这个项目试图将函数式编程的魔力带入日常的 Java 世界

    "Javaz:这个项目试图将函数式编程的魔力带入日常的 Java 世界" 恰好响应了这一需求,它为Java开发者提供了一种工具或库,以更好地利用函数式编程的思想和技巧。 函数式编程的核心理念是将计算视为纯函数的组合,...

    java实用编程100(1)例1-55

    9. **函数式编程**:Java 8引入了Lambda表达式,使得函数式编程风格成为可能。实例可能展示如何使用Lambda简化代码,以及流API的应用。 10. **反射机制**:Java的反射API允许程序在运行时动态获取类的信息并操作类...

    java100例编程源代码

    9. **函数式编程**:Java 8引入了Lambda表达式和Stream API,提供了函数式编程风格。例子可能包括使用这些新特性进行数据处理和并行计算。 10. **网络编程**:Java的Socket编程允许创建客户端和服务器应用程序。...

    Java实用教程第章Java语言及编程环境.pptx

    - Lambda表达式:引入函数式编程,简化代码,增加语言灵活性。 - 新的时间日期API:改进日期时间处理能力。 - 流API:支持管道操作,配合lambda表达式优化数据处理。 - 接口默认方法:接口可以提供默认实现,...

    java编程艺术代码

    12. **Lambda表达式**:自Java 8开始引入的lambda表达式简化了函数式编程,代码示例将展示如何使用lambda简化匿名内部类,以及函数式接口的使用。 13. **模块系统**:Java 9引入了模块系统,有助于组织大型项目和...

    Head First Java 3rd (英文版)

    书中特别强调了Java 8及更高版本引入的重要特性,如Java流(Java Streams)和函数式编程(Functional Programming)。Java流提供了一种处理大量数据的新方式,允许程序员以更简洁、高效的方式操作集合。而Lambda...

    study_fp_with_kotlin:使用Kotlin学习函数式编程

    3. **尾递归优化**: Kotlin对尾递归进行了优化,使得无限递归可以转化为循环,避免栈溢出问题,这是函数式编程中常用的技术。 4. **序列(Sequence)**: Kotlin的`sequence`构造器允许延迟计算,类似于Java 8的...

    java api1.8中文谷歌翻译

    在Java 1.8中,引入了许多关键的新特性,如Lambda表达式、函数式编程、Stream API、Date和Time API的改进以及接口的默认方法等。以下是对这些重要知识点的详细解释: 1. Lambda表达式:Lambda表达式是Java 8的核心...

Global site tag (gtag.js) - Google Analytics