Java8 函数式编程

1. 概述

1.1 函数式编程简介

常见的编程范式:

命令式编程(Imperative Programming),逻辑式编程(Logic Programming),函数式编程(Functional Programming)。

函数式编程作为一种编程范式,在科学领域,是一种编写计算机程序数据结构和元素的方式,它把计算过程当做是数学函数的求值,而避免更改状态和可变数据。

什么是函数式编程?简单的回答:一切都是数学函数。函数式编程语言里也可以有对象,但通常这些对象都是恒定不变的 ——

要么是函数参数,要什么是函数返回值。函数式编程语言里没有 for/next

循环,因为这些逻辑意味着有状态的改变。相替代的是,这种循环逻辑在函数式编程语言里是通过递归、把函数当成参数传递的方式实现的。

举个例子:

a = a +1

这段代码在普通成员看来并没有什么问题,但在数学家看来确实不成立的,因为它意味着变量值得改变。

1.2 Lambda 表达式简介

2.1 Lambda 表达式的形式

Java 中 Lambda 表达式一共有五种基本形式,具体如下:

Runnable noArguments = () -> System.out.println("Hello World");

ActionListener oneArgument = event -> System.out.println("button clicked");

Runnable multiStatement = () -> {    System.out.print("Hello");    System.out.println(" World");};

BinaryOperator add = (x, y) -> x + y;

BinaryOperator addExplicit = (Long x, Long y) -> x + y;

➊中所示的 Lambda 表达式不包含参数,使用空括号 () 表示没有参数。该 Lambda 表达式 实现了 Runnable

接口,该接口也只有一个 run 方法,没有参数,且返回类型为 void。➋中所示的 Lambda

表达式包含且只包含一个参数,可省略参数的括号,这和例 2-2 中的 形式一样。Lambda

表达式的主体不仅可以是一个表达式,而且也可以是一段代码块,使用大括号

({})将代码块括起来,如➌所示。该代码块和普通方法遵循的规则别无二致,可以用返 回或抛出异常来退出。只有一行代码的 Lambda

表达式也可使用大括号,用以明确 Lambda表达式从何处开始、到哪里结束。Lambda

表达式也可以表示包含多个参数的方法,如➍所示。这时就有必要思考怎样去阅 读该 Lambda

表达式。这行代码并不是将两个数字相加,而是创建了一个函数,用来计算 两个数字相加的结果。变量 add 的类型是 BinaryOperator

记住一点很重要,Lambda 表达式都可以扩写为原始的“匿名类”形式。所以当你觉得这个 Lambda 表达式很复杂不容易理解的时候,不妨把它扩写为“匿名类”形式来看。

2.2 闭包

如果你以前使用过匿名内部类,也许遇到过这样的问题。当你需要匿名内部类所在方法里的变量,必须把该变量声明为final。如下例子所示:

final String name = getUserName();

button.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent event){        System.out.println("hi "+ name);    }});

Java 8放松了这一限制,可以不必再把变量声明为final,但其实该变量实际上仍然是final的。虽然无需将变量声明为 final,但在 Lambda 表达式中,也无法用作非终态变量。如果坚持用作非终态变量(即改变变量的值),编译器就会报错。

2.3 函数接口

上面例子里提到了ActionListener接口,我们看一下它的代码:

publicinterfaceActionListenerextendsEventListener{/**

    * Invoked when an action occurs.

    */publicvoidactionPerformed(ActionEvent e);}

ActionListener只有一个抽象方法:actionPerformed,被用来表示行为:接受一个参数,返回空。记住,由于actionPerformed定义在一个接口里,因此abstract关键字不是必需的。该接口也继承自一个不具有任何方法的父接口:EventListener。

我们把这种接口就叫做函数接口。

JDK 8 中提供了一组常用的核心函数接口:

接口参数返回类型描述

PredicateTboolean用于判别一个对象。比如求一个人是否为男性

ConsumerTvoid用于接收一个对象进行处理但没有返回,比如接收一个人并打印他的名字

FunctionTR转换一个对象为不同类型的对象

SupplierNoneT提供一个对象

UnaryOperatorTT接收对象并返回同类型的对象

BinaryOperator(T, T)T接收两个同类型的对象,并返回一个原类型对象

其中Cosumer与Supplier对应,一个是消费者,一个是提供者。

Predicate用于判断对象是否符合某个条件,经常被用来过滤对象。

Function是将一个对象转换为另一个对象,比如说要装箱或者拆箱某个对象。

UnaryOperator接收和返回同类型对象,一般用于对对象修改属性。BinaryOperator则可以理解为合并对象。

如果以前接触过一些其他 Java 框架,比如 Google Guava,可能已经使用过这些接口,对这些东西并不陌生。所以,其实 Java 8 的改进并不是闭门造车,而是集百家之长。

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