龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > JAVA开发 >

Java函数式编程(一):你好,Lambda表达式(6)

时间:2014-09-26 03:26来源:网络整理 作者:网络 点击:
分享到:
变量可变的代码会有很多活动路径。改的东西越多,越容易破坏原有的结构,并引入更多的错误。有多个变量被修改的代码难于理解也很难进行并行化。不

变量可变的代码会有很多活动路径。改的东西越多,越容易破坏原有的结构,并引入更多的错误。有多个变量被修改的代码难于理解也很难进行并行化。不可变性从根本上消除了这些烦恼。 Java支持不可变性但没有强制要求——但我们可以。我们需要改变修改对象状态这个旧习惯。我们要尽可能的使用不可变的对象。 声明变量,成员和参数的时候,尽量声明为final的,就像Joshua Bloch在” Effective Java“里说的那句名言那样,“把对象当成不可变的吧”。 当创建对象的时候,尽量创建不可变的对象,比如String这样的。创建集合的时候,也尽量创建不可变或者无法修改的集合,比如用Arrays.asList()和Collections的unmodifiableList()这样的方法。 避免了可变性我们才可以写出纯粹的函数——也就是,没有副作用的函数。

避免副作用

假设你在写一段代码到网上去抓取一支股票的价格然后写到一个共享变量里。如果我们有很多价格要抓取,我们得串行的执行这些费时的操作。如果我们想借助多线程的能力,我们得处理线程和同步带来的麻烦事,防止出现竞争条件。最后的结果是程序的性能很差,为了维护线程而废寝忘食。如果消除了副作用,我们完全可以避免这些问题。 没有副作用的函数推崇的是不可变性,在它的作用域内不会修改任何输入或者别的东西。这种函数可读性强,错误少,容易优化。由于没有副作用,也不用再担心什么竞争条件或者并发修改了。不仅如此,我们还可以很容易并行执行这些函数,我们将在145页的来讨论这个。

优先使用表达式

语句是个烫手的山芋,因为它强制进行修改。表达式提升了不可变性和函数组合的能力。比如,我们先用for语句计算折扣后的总价。这样的代码导致了可变性以及冗长的代码。使用map和sum方法的表达性更强的声明式的版本后,不仅避免了修改操作,同时还能把函数串联起来。 写代码的时候应该尽量使用表达式,而不是语句。这样使得代码更简洁易懂。代码会顺着业务逻辑执行,就像我们描述问题的时候那样。如果需求变动,简洁的版本无疑更容易修改。

使用高阶函数进行设计

Java不像Haskell那些函数式语言那样强制要求不可变,它允许我们修改变量。因此,Java不是,也永远不会是,一个纯粹的函数式编程语言。然而,我们可以在Java里使用高阶函数进行函数式编程。 高阶函数使得重用更上一层楼。有了高阶函数我们可以很方便的重用那些小而专,内聚性强的成熟的代码。 在OOP中我们习惯了给方法传递给对象,在方法里面创建新的对象,然后返回对象。高阶函数对函数做的事情就跟方法对对象做的一样。有了高阶函数我们可以。

1.把函数传给函数
2.在函数内创建新的函数
3.在函数内返回函数

我们已经见过一个把函数传参给另一个函数的例子了,在后面我们还会看到创建函数和返回函数的示例。我们先再看一遍“把函数传参给函数”的那个例子:

复制代码 代码如下:

prices.stream()
.filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0) .map(price -> price.multiply(BigDecimal.valueOf(0.9)))
report erratum • discuss
.reduce(BigDecimal.ZERO, BigDecimal::add);

在这段代码中我们把函数price -> price.multiply(BigDecimal.valueOf(0.9)),传给了map函数。传递的这个函数是在调用高阶函数map的时候才创建的。通常来说一个函数有函数体,函数名,参数列表,返回值。这个实时创建的函数有一个参数列表后面跟着一个箭头(->),然后就是很短的一段函数体了。参数的类型由Java编译器来进行推导,返回的类型也是隐式的。这是个匿名函数,它没有名字。不过我们不叫它匿名函数,我们称之为lambda表达式。 匿名函数作为传参在Java并不算是什么新鲜事;我们之前也经常传递匿名内部类。即使匿名类只有一个方法,我们还是得走一遍创建类的仪式,然后对它进行实例化。有了lambda表达式我们可以享受轻量级的语法了。不仅如此,我们之前总是习惯把一些概念抽象成各种对象,现在我们可以将一些行为抽象成lambda表达式了。 用这种编码风格进行程序设计还是需要费些脑筋的。我们得把已经根深蒂固的命令式思维转变成函数式的。开始的时候可能有点痛苦,不过很快你就会习惯它了,随着不断的深入,那些非函数式的API逐渐就被抛到脑后了。 这个话题就先到这吧,我们来看看Java是如何处理lambda表达式的。我们之前总是把对象传给方法,现在我们可以把函数存储起来并传递它们。 我们来看下Java能够将函数作为参数背后的秘密。

第五节:加了点语法糖

精彩图集

赞助商链接