From 01d74ec40b100d56ee9c2a23655d120b9b9e5835 Mon Sep 17 00:00:00 2001 From: LingCoder Date: Sun, 24 Mar 2019 23:45:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=AC=AC=E5=8D=81=E4=B8=89?= =?UTF-8?q?=E7=AB=A0=E7=9B=AE=E5=BD=95=E5=AD=90=E6=A0=87=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SUMMARY.md | 18 +++++++++--------- book/13-Functional-Programming.md | 31 +++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/SUMMARY.md b/SUMMARY.md index d4caa14..1a6838e 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -161,15 +161,15 @@ * [for-in和迭代器](book/12-Collections.md#for-in和迭代器) * [本章小结](book/12-Collections.md#本章小结) * [第十三章 函数式编程](book/13-Functional-Programming.md) - * [](book/13-Functional-Programming.md#) - * [](book/13-Functional-Programming.md#) - * [](book/13-Functional-Programming.md#) - * [](book/13-Functional-Programming.md#) - * [](book/13-Functional-Programming.md#) - * [](book/13-Functional-Programming.md#) - * [](book/13-Functional-Programming.md#) - * [](book/13-Functional-Programming.md#) - * [](book/13-Functional-Programming.md#) + * [旧vs新](book/13-Functional-Programming.md#旧vs新) + * [Lambda表达式](book/13-Functional-Programming.md#Lambda表达式) + * [方法引用](book/13-Functional-Programming.md#方法引用) + * [函数式接口](book/13-Functional-Programming.md#函数式接口) + * [高阶函数](book/13-Functional-Programming.md#高阶函数) + * [闭包](book/13-Functional-Programming.md#闭包) + * [函数组合](book/13-Functional-Programming.md#函数组合) + * [Currying和Partial-Evaluation](book/13-Functional-Programming.md#Currying和Partial-Evaluation) + * [纯函数式编程](book/13-Functional-Programming.md#纯函数式编程) * [本章小结](book/13-Functional-Programming.md#本章小结) * [第十四章 流式编程](book/14-Streams.md) * [](book/14-Streams.md#) diff --git a/book/13-Functional-Programming.md b/book/13-Functional-Programming.md index 097bff5..2eb5ea0 100644 --- a/book/13-Functional-Programming.md +++ b/book/13-Functional-Programming.md @@ -1,6 +1,7 @@ [TOC] -# 第十三章-函数式编程 + +# 第十三章 函数式编程 @@ -28,9 +29,10 @@ OO (object oriented) 是抽象数据,FP (functional programming) 是抽象行 FP的想法值得融入非FP语言。 例如,这种情况发生在Python语言中。 Java 8在FP中添加了自己的功能,我们将在此章探讨。 - -## 旧 VS 新 + +## 旧vs新 + 通常,方法会根据我们传递的数据产生不同的结果。 如果您希望某个方法在从一个调用到下一个调用时表现不同,该怎么办? 如果我们将代码传递给方法,我们可以控制它的行为。 以前,我们通过在方法中创建包含所需行为的对象,然后将该对象传递给我们想要控制的方法来完成此操作。 以下示例显示了这一点,然后添加了 Java 8方法:方法引用和 lambda 表达式。 @@ -110,7 +112,10 @@ Hello there Hello there 在Java 8之前,我们已经能够通过[1]和[2]传递功能。但是,写入和读取的语法非常笨拙,我们只在强制时才这样做。 方法引用和lambda表达式可以在您需要时传递功能,而不是仅在必要时传递功能。 -## Lambda 表达式 + + +## Lambda表达式 + Lambda表达式是使用最小可能语法编写的函数定义: @@ -273,9 +278,9 @@ public class RecursiveFibonacci { 将Fibonacci 序列对中的最后两个元素求和来产生下一个元素。 - ## 方法引用 + Java 8 方法引用指的是没有以前版本的 Java 所需的额外包袱的方法。 方法引用是类名或对象名,后面跟 :: [^4],然后是方法的名称。 ```java @@ -523,8 +528,10 @@ public class CtorReference { 编译器可以看到调用函数方法( 在本例中为make())意味着调用构造函数。 + ## 函数式接口 + 方法引用和lambda表达式都是必须赋值的,并且这些赋值需要编译器的类型信息以确保类型正确性。 Lambda表达式特别引入了新的要求。 考虑: ```java @@ -889,9 +896,9 @@ public interface IntToDoubleFunction { 当然,如果由于缺少原始类型的函数而导致性能实际上成为问题,您可以轻松编写自己的接口( 使用Java库源进行参考 ) - 尽管这似乎不太可能是您的性能瓶颈。 - ## 高阶函数 + 这个名字听起来有点令人生畏,但是:高阶函数只是一个消耗或产生函数的函数。 我们先来看看产生一个函数: @@ -984,8 +991,10 @@ O 在这里,**transform()**生成一个与传入的函数具有相同签名的函数,但是您可以生成任何您想要的类型。这在 **Function** 接口中使用名为 **andThen()**的默认方法,该方法专门用于操作函数。 顾名思义,在调用in函数之后调用 **toThen()**(还有 **compose()**,它在 **in** 函数之前应用新函数)。 要附加一个**andThen()**函数,我们只需将该函数作为参数传递。 **transform()**产生的是一个新函数,它将 **in** 的动作与 **andThen()**参数的动作结合起来。 + ## 闭包 + 在上一节的 **ProduceFunction.java** 中,我们从方法返回了一个 lambda 函数。 这个例子让事情变得简单,但是我们必须在返回 lambdas 时探讨一些问题。 *闭包*一词概括了这些问题。 闭包非常重要,因为它们可以轻松生成函数。 @@ -1236,9 +1245,9 @@ public class AnonymousClosure { 事实证明,只要有内部类,就会有闭包(Java 8只 会使闭包变得更容易)。 在 Java 8 之前,要求是 **x** 和 **i** 被明确声明为 **final**。 使用 Java 8,内部类的规则已经放宽,包括 “effectively final”。 - ## 函数组合 + 函数组合基本上意味着“将函数粘贴在一起以创建新函数”,它通常被认为是函数编程的一部分。您在**TransformFunction.java** 中看到了一个使用 **andThen()** 的函数组合示例。一些 **java.util** 的函数接口包含支持函数组合的方法。 Compositional Supporting Method Interfaces Function BiFunction Consumer BiConsumer IntConsumer andThen(argument) Performs the original LongConsumer operation followed by DoubleConsumer the argument operation. @@ -1309,8 +1318,8 @@ foobaz 你可以从输出中看到 **p4** 是如何工作的:任何带有 “foo ”的东西都会存活,即使它的长度大于5。 “fongopuckey” 太长了,没有 “bar” 来保存它。 +## Currying和Partial-Evaluation -## Currying 和 Partial Evaluation *Currying* 以 Haskell Curry 命名,Haskell Curry 是其发明者之一,可能是唯一一个以他的名字命名的重要事物的计算机领域的人物(另一个是 Haskell 编程语言)。 Currying 意味着从一个函数开始,该函数接受多个参数,并将其转换为一系列函数,每个函数只接受一个参数。 @@ -1405,14 +1414,16 @@ public class CurriedIntAdd { 您可以在因特网上找到更多 currying 示例。 通常这些是 Java 以外的语言,但如果你理解它们的基本概念,它们应该很容易翻译。 - ## 纯函数式编程 + 在没有函数支持的情况下,即使用像C这样的原始语言,也可以按照一定的原则编写纯函数程序。Java使它比这更容易,但是您必须小心地使一切都成为 **final**,并确保您的所有方法和函数没有副作用。因为 Java 本质上不是一种不可变的语言,所以如果您犯了错误,编译器不会提供任何帮助。 有第三方工具可以帮助您[^9],但是使用 **Scala** 或 **Clojure** 这样的语言可能更容易,因为它们从一开始就是为保持不变性而设计的。这些语言使您可以用 Java 编写项目的一部分,如果您必须用纯函数式编写,则可以用**Scala** 编写其他部分 (这需要一些规则) 或 **Clojure** (这需要的少得多)。虽然您将在并发编程一章中看到 Java确实支持并发,但是如果这是您项目的核心部分,您可能会考虑至少在项目的一部分中使用 **Scala** 或 **Clojure**之类的语言。 -## 总结 + +## 本章小结 + Lambda 表达式和方法引用并没有将 Java 转换成函数式语言,而是提供了对函数式编程的支持。它们对 Java 是一个巨大的改进,因为它们允许您编写更简洁、更干净、更容易理解的代码。在下一章中,您将看到它们如何启用流。如果你像我一样,你会喜欢流媒体。