java函数的编写-编写_strcpy函数解决步骤
这是最近阅读《Programming in Scala》后的感悟。 这是文本:
函数式编程和面向对象编程并不冲突,非常函数式的代码仍然可以用 Java 编写。 (可以参考《Java函数式编程》)
真正不兼容的其实是描述式和祈使式。
描述性与命令性
例如,给定一个 Int 列表,找出每个元素的总和。 如果你用命令式的方式写java函数的编写,从 sum = 0 开始,接着是 i = 0,最后 for 循环结束。
当用描述性的方式书写时,“列表的元素之和”等于“列表的第一个元素”加上“列表的其余元素组成的列表元素之和”。
假设链表的第一个元素用head表示java函数的编写,取链表剩余元素组成的链表用tail表示。 那么伪代码如下:
总和(列表)= {
如果(alist!=空)返回0
否则返回 head(alist) + sum(tail(alist))
}
可见描述式和递归是一种比较自然的结合。 难怪 FP 语言喜欢用递归。
参考透明度
遵循函数式风格的另一个好处是您可以编写“引用透明”的函数。 也就是说,这个函数调用的结果可以等价地被这个函数的返回值代替。
比如代码中有一段:a + sum(b, c),如果b和c分别等于2和3,那么相当于直接写a + 5。可能是因为这个例子太简单了而且是数值计算,一般人自然能写出这种引用透明的函数。
但是,如果是一段业务代码,你能保证不会在函数中调用Spring bean读写数据库吗? 你能保证不修改某个全局变量或者ThreadLocal吗? 你能保证不调用带入参的set方法吗?
另一种提及透明度的方式是“无副作用”,上面列出的一些示例是副作用的示例。
没有副作用的代码更容易测试和重构,并且引入的错误更少。 想一想,是不是经常会发现某个字段,经过一系列的函数调用,在某个时候被设置为不符合预期的值,进而导致一系列莫名其妙的问题?
不可变数据
上面提到的最后一个例子有个特殊的名字叫做别名问题,那么函数式编程风格是如何避免此类问题的呢? 答案是使用不可变数据。
通过将一个类的所有字段设置为final,这个类就是一个不可变类(如果有一个Map的字段是final的,如果非要修改这个Map,那就是强硬路线)。
相应的,函数体中也不能再设置各种字段。 一旦需要更改某些内容,应该通过返回该类的新实例来完成。
事实上,对于大多数程序员来说,问题是,不可变数据可以编程吗? 看看Java的String,看看Spark的RDD。