《编程导论(Java)·3.1.2 方法》之 副作用
2015-07-11 17:18
661 查看
4. 副作用
在一些语言如Pascal中,子程序被分成两种:函数和过程。虽然Java没有强制性地要求将方法区分为命令和函数,然而这种区别对于良好地设计程序有很大的帮助[1]。
首先说明一个概念:副作用(side effect)。副作用一般是针对操作(表达式)而言的,一个操作/表达式有“副作用”是指在对该表达式求值时,会改变程序的一个或多个数据,以致再次对该表达式求值时,可能会得出不同的结果。事实上,Java的4种表达式语句如赋值、自增自减、方法调用、对象创建都可能带来副作用。
这里讨论方法的副作用。一个方法的执行,如果在返回一个值之外还导致某些外部“状态”发生变化,则称该方法产生了副作用。这里所谓“状态”发生变化,可以是实例域或静态变量被修改、方法的实参被修改(Java 中不会出现这种情况。但是实参为引用时,其指向的对象可能被修改从而产生副作用)、将数据传递给显示器、打印机或存入文件中等等。
当然,方法内部的表达式也会出现副作用,如果它仅仅影响局部变量而不影响外部状态,则方法没有副作用。基于副作用概念,定义两个术语:
² 有返回值而且没有副作用的方法称为函数(function)。
² 没有返回值的方法必然有副作用,除非它的方法体是空的或者方法没有意义。所以,没有返回值的方法、有返回值但有副作用的方法称为过程(procedure)或命令(command)。简言之,有副作用的方法称为过程。
如此严格地定义出函数的概念,是因为函数使得系统的状态稳定,函数的行为容易预测。更进一步,如果函数是纯粹的函数(pure function,纯函数)——它的输出值依靠和仅仅依靠其输入、对于相同的输入总是返回相同的值,(由于纯函数的纯粹和无副作用)对纯函数的调用就能够被一个值取代(或者说,将方法视为一个值),这就是函数式编程语言中著名的引用透明(referentialtransparency)特性。
在函数式编程语言(functionalprogramming language)如Haskell[2]中,尤其强调避免副作用。当然了,完全不产生副作用的编程语言是没有任何用处的,例如数据显示和存入文件等等副作用都是必要的,强调无副作用的Haskell 语言,使用一种技术将它们分离出来,用一种安全的方式单独执行。
Java是命令式面向对象语言,但能够借鉴函数式语言的优点,也期待Java中加入重要的函数式语言的特性。随着Java 8的发布,引入的λ表达式(Lambda Expressions)表明,Java开始大力引入函数式语言的特性。(They enable you to treat functionality as a method argument, or code as data.)
[1] 参考RichardMitchell,Jim Mackim著,孟岩译,Design by Contract原则与实践。
[2] http://www.haskell.org/learning.html
在一些语言如Pascal中,子程序被分成两种:函数和过程。虽然Java没有强制性地要求将方法区分为命令和函数,然而这种区别对于良好地设计程序有很大的帮助[1]。
首先说明一个概念:副作用(side effect)。副作用一般是针对操作(表达式)而言的,一个操作/表达式有“副作用”是指在对该表达式求值时,会改变程序的一个或多个数据,以致再次对该表达式求值时,可能会得出不同的结果。事实上,Java的4种表达式语句如赋值、自增自减、方法调用、对象创建都可能带来副作用。
这里讨论方法的副作用。一个方法的执行,如果在返回一个值之外还导致某些外部“状态”发生变化,则称该方法产生了副作用。这里所谓“状态”发生变化,可以是实例域或静态变量被修改、方法的实参被修改(Java 中不会出现这种情况。但是实参为引用时,其指向的对象可能被修改从而产生副作用)、将数据传递给显示器、打印机或存入文件中等等。
当然,方法内部的表达式也会出现副作用,如果它仅仅影响局部变量而不影响外部状态,则方法没有副作用。基于副作用概念,定义两个术语:
² 有返回值而且没有副作用的方法称为函数(function)。
² 没有返回值的方法必然有副作用,除非它的方法体是空的或者方法没有意义。所以,没有返回值的方法、有返回值但有副作用的方法称为过程(procedure)或命令(command)。简言之,有副作用的方法称为过程。
如此严格地定义出函数的概念,是因为函数使得系统的状态稳定,函数的行为容易预测。更进一步,如果函数是纯粹的函数(pure function,纯函数)——它的输出值依靠和仅仅依靠其输入、对于相同的输入总是返回相同的值,(由于纯函数的纯粹和无副作用)对纯函数的调用就能够被一个值取代(或者说,将方法视为一个值),这就是函数式编程语言中著名的引用透明(referentialtransparency)特性。
例程 3‑3纯函数 package semantics.method; public class SideEffectsDemo{ private static int x = 0; //纯函数(pure function) public static int times(int i,int j){ return i * j ; } //非纯函数 public static int m(int i,int j){ return i * j +x; } }
在函数式编程语言(functionalprogramming language)如Haskell[2]中,尤其强调避免副作用。当然了,完全不产生副作用的编程语言是没有任何用处的,例如数据显示和存入文件等等副作用都是必要的,强调无副作用的Haskell 语言,使用一种技术将它们分离出来,用一种安全的方式单独执行。
Java是命令式面向对象语言,但能够借鉴函数式语言的优点,也期待Java中加入重要的函数式语言的特性。随着Java 8的发布,引入的λ表达式(Lambda Expressions)表明,Java开始大力引入函数式语言的特性。(They enable you to treat functionality as a method argument, or code as data.)
练习3-5:何谓方法、函数、纯函数? 解释副作用的含义。 |
练习3-6:实现方法,求f(x)=x^3 + 3x+1。注:书中x^3表示x*x*x. |
[2] http://www.haskell.org/learning.html
相关文章推荐
- java-泛形使用
- maven工程使用spring-boot-devtools进行热部署,更改代码避免重启web容器
- java观察者模式
- SpringMVC笔记3--annotation
- java单例 生成唯一的标识
- Java系列学习(十三)-字符串
- Eclipse + CDT引入OpenCV失败的解决办法
- SpringMVC笔记2--ViewResolver
- 解决spring-mvc @responseBody注解返回json 乱码问题
- spring mvc头
- 具体分析Struts工作流程
- Java基础-- Java API
- Java的bin等目录说明
- Java8对《编程导论(Java)》的影响
- 20个非常有用的Java程序片段
- IntelliJ IDEA导出Java 可执行Jar包
- Java算法之二分法和排序算法
- Java tutorial 6
- SpringMVC源码剖析(五)-消息转换器
- 剖析springmvc之HelloWorld