5.3 函数式编程和命令式编程

从本质上说,Java是一种命令式编程语言。在命令式编程语言中,变量通常是可修改的,而类通常保存了内部状态。在Java中,POJO(Plain Old Java Object)是命令式编程的典范。标准POJO包含可通过调用设置方法随便修改的变量,可访问POJO实例的任何代码都可修改其变量。这可能导致难以发现的微妙bug,多个线程试图同时修改同一个变量时尤其如此。

在函数式编程中是这样编写代码的,即确保在程序运行期间不会修改任何既有的变量。值是以函数参数的方式指定的,而输出是根据参数生成的。每次调用函数时,只要指定的参数相同,输出就必须相同。

下面来看一个非常简单的示例。请不要过多地关注其中的语法,因为本章后面将详尽地介绍Scala语言的语法。先来看一个传统的Scala面向对象编程示例:

  1. class AddDemoOOP {
  2. var x = 0
  3. def add(y: Int): Int = {
  4. x += y
  5. x
  6. }
  7. }
  8. val a = new AddDemoOOP()
  9. print(a.add(1))
  10. print(a.add(1))

这将打印12。虽然两次调用时方法add接受的参数相同(都是整数1),但它们返回的值不同。这是因为这个方法修改了类的状态。在纯粹的函数式编程中,这是不允许的。下面是这个类的函数式版本:

  1. class AddDemoFunctional {
  2. def add(x: Int, y: Int): Int = {
  3. x + y
  4. }
  5. }
  6. val b = new AddDemoFunctional
  7. print(b.add(0, 1))
  8. print(b.add(0, 1))

这将打印1两次。这个版本的类没有存储任何内部状态。要让方法add返回不同的值,必须给它传递不同的参数。

5.3 函数式编程和命令式编程 - 图1 注意,Scala虽然是纯粹的OOP语言,但并不是纯粹的函数式编程语言。如第一个示例所示,使用Scala很容易编写不遵循函数式编程规则的代码。

编写使用多个线程的程序时,函数式编程是一种流行的选择。由于方法不能修改在多个线程中使用的数据结构的状态,因此函数式编程通常比命令式编程安全得多,但这要求开发人员使用不同的思维方式。

有关函数式编程可说的还有很多,本章后面将介绍其他一些与此相关的主题。

5.3 函数式编程和命令式编程 - 图2 不同于众多其他的函数式编程语言,Scala让你能够按自己的步伐学习函数式编程,因为它是纯粹的面向对象编程语言。