函数式编程及Lamda

函数式编程

定义

函数式编程(funcational programming)属于结构化编程的一种。主要思想是把运算过程尽量写成一系列嵌套的函数调用。

结构化编程
一种编程范型,采用子程序、代码区块、for循环以及while循环 等结构来取代传统的goto

函数式编程关心数据的映射,命令式编程关心解决问题的步骤。

特点
  1. 函数是“第一等公民”
    函数和其他数据类型一样,可以赋值给其他变量,作为其他函数的传入参数或返回值。

  2. 只用“表达式”,不用“语句”
    “expression” 是一个单纯的运算过程,总是有返回值。“statement”是执行某种操作,没有返回值。

  3. 没有“副作用”
    “副作用”是指函数内部有与外部的互动,产生运算以外的其他结果。函数要保持独立,所有功能返回一个新的值,尤其不得修改外部变量的值。

纯函数是这样一种函数,即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。

  1. 不修改状态
    函数式编程使用参数保存状态,只返回新的值,不修改系统变量。

  2. 引用透明(Referential transparency)
    函数的运行不依赖外部变量或“状态”,只依赖输入参数。只要参数相同,引用函数返回值总是相同的。

构成
  • 高阶函数(higher-order function)
    能够接受一个函数作为参数的函数。

  • 函子(Functor)
    函子是函数式编程里最重要的数据类型,也是基本的运算单位和功能单位。
    函子是指具有map方法的容器,包含了值和变形关系。map方法将容器里面的每一个值,映射到另一个容器。即将一个范畴转换成令一个范畴。

构成范畴这种数据模型的要素:
所有成员是一个集合
变形关系是函数

  • 闭包(Closure)
    闭包就是能够读取其他函数内部变量的函数,可简单理解成"定义在一个函数内部的函数"。当内嵌函数体内引用到体外的变量时,将会把定义时涉及到的引用环境和函数体打包成一个整体(闭包)返回。
    类是有行为的数据,闭包是有数据的行为。
    闭包是由函数及其相关的引用环境组合而成的实体,即闭包=函数+引用环境
参考

函数式编程入门教程
函数式编程初探
学习Javascript闭包(Closure)

lambda

lambda表达式通常在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。参考

Lambda表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。

JAVA中的lambda

Java8之前,传递行为的唯一方法就是通过匿名内部类。Java中的lamda不是一个匿名内部类的语法糖。在匿名类中,this指代的是匿名类本身;而在lambda表达式中,this指代的是lambda表达式所在的这个类。

1.lambda表达式
只有那些仅仅包含一个非实例化抽象方法的接口才能使用lambda表达式。Runnable接口就是函数式接口的一个例子。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Java8默认带有许多可以直接在代码中使用的函数式接口,它们位于java.util.function包中。

2.lambda表达式结构
-> 是用来把参数从函数体中分离出来的操作符。
在lambda表达式中,我们不需要明确指出参数类型,javac编译器会通过上下文自动推断参数的类型信息。根据上下文推断类型的行为称为类型推断

3.方法引用
当需要为一个特定方法创建lambda表达式,比如Function strToLength = String::length;,可以用缩写符号表示。String是目标引用,::是定界符,length是目标引用的方法。该方法可以是静态或者实例方法。
参考原文

4.实现机制
采用在Java7中新增的动态启用来延迟在运行时的加载策略。当javac编译代码时,捕获代码中的lambda表达式并生成一个动态启用的调用地址(称lambda工厂)。当动态启用被调用时,就会向lambda表达式发生转换的地方返回一个函数式接口的实例。

JAVA中的Stream

Stream是Java 8 提供的高效操作集合类(Collection)数据的API。Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对JAVA集合运算和表达的高阶抽象。

  1. Collection对比
    Java8运行开发者使用stream方法基于Collection集合创建一个Stream管道。Stream采用内部迭代。
    CollectionStream处理集合方式的不同:

    Collection与Stream处理集合方式的不同

  2. 懒加载
    Stream不会储存数据,懒加载(只有在被使用到时才会执行计算)。Stream表达式在被末端操作方法调用之前不会被赋值计算。

  • 过渡操作:从已存在的stream上产生另一个新的stream的函数,比如filter,map,sorted
  • 末端操作:从stream上产生一个非stream结果的函数,比如collect(toList()),forEach,count,get

参考原文

感想

在一棵树上吊死是大多数非理性死忠的表现。

你可能感兴趣的:(函数式编程及Lamda)