函数式编程与Lambda表达式(上)

Posted QThink

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数式编程与Lambda表达式(上)相关的知识,希望对你有一定的参考价值。

正如开篇中提到的,Lambda表达式是Java8版本最重要的特性,因为它将函数式编程思想引入了Java。那函数式编程思想有那么重要?

大家都知道Java是面向对象语言,面向对象编程是对数据进行抽象,但现实世界中除了数据,其实还有行为,而函数式编程就是对行为进行抽象。

引入函数式编程思想后,Java程序员可以使用新的工具来对现实世界进行建模。既然如此重要,接下来就跟着Q君认真学习函数式编程吧。

1、什么是函数式编程

函数式编程,顾名思义就是一种使用函数进行编程的方式。那什么是函数呢?我们很容易想到数学中的函数,比如y=f(x),它接受输入值x,产生输出值y,并且不会有任何副作用。

在数学函数y=f(x)中,最重要的是对应法则f,它是函数关系的本质特征,也可以说是函数的行为。对于x来说,使用不同的f处理,产生的y也是不同的。你可以把f当做黑盒,如果想得到特定的结果只需要选择指定的f,输入值即可,不需要关心f内部是如何处理的。

从以上描述中可以看出,使用函数编程你只需要关心做什么,而不用考虑如何做(如何实现的细节留给系统函数库),并且还不会产生副作用。这跟我们常用的命令式编程有很大区别,后者专注于如何实现。

采用函数式编程的好处很明显,用这种方式编写的代码更接近问题陈述,自然也就更容易理解。由于如何实现由系统选择,代码也就更健壮,并且无副作用。总之,使用函数式编程能帮助你更容易地构建和维护系统。

2、Java中的函数

在谈函数之前,先说下Java中值的概念。Java中的值可以是原始值,对象,由于编程语言的整个目的就在于操作值,因此按照历史上编程语言的传统,这些值被称为一等值或一等公民。

编程语言的其他结构也许有助于我们表示值的结构,但在程序执行期间不能传递,因而是二等公民,比如Java中的方法和类等。

不过,随着编程语言的发展,很多新的函数式编程语言开始将方法等概念作为一等值并取得很好的效果,比如Scala和Groovy。并且,一旦程序员熟悉这种强大的功能,他们就再也不愿意使用没有该功能的语言。这是很要命的,所以Java8新增了函数-值的一种新形式,以允许程序员将方法作为值来传递。

Java中的函数其实不能算新的类型,因为Java没有像其他语言那样提供“函数类型”来描述函数的类型,你也就不能通过声明表示函数。不过,Java提供了其他方式来支持方法作为函数值传递,比如方法引用,lambda表达式。

你可以将Java中的函数理解为Java8为了让方法等概念作为一等值而引入的,更多的是为了让大家熟悉函数作为值的思想,熟练使用函数式编程的工具。

3、行为参数化

为了传递函数或方法,Java8增加了一种新的能力:把方法或代码作为参数传递给另一个方法,这一概念称为行为参数化。通过将行为作为参数传递给方法,可以让方法具有不同的行为,以适应未来不断变化的需求。

在Java8之前,你可以通过抽象类或匿名内部类来传递代码。比如实现一个筛选绿苹果的功能,采用匿名类的解决方案可能是下面这样的:

 public static List<Apple> filterApples(List<Apple> apples, ApplePredicate p) {
       List<Apple> result = new ArrayList<Apple>();
       for (Apple apple : apples) {
           if (p.test(apple)) {
               result.add(apple);
           }
       }
       return result;
   }

   public static void main(String[] args) {
       List<Apple> apples = Arrays
               .asList(new Apple("Green"), new Apple("Red"));
       filterApples(apples, new ApplePredicate() {
           @Override
           public boolean test(Apple apple) {
               return "Green".equals(apple.getColor());
           }
       });
   }

如果后续根据其他条件筛选苹果,比如重量,你只需要实现ApplePredicate添加相应处理逻辑即可。也就是说,你把filterApples方法的行为参数化了。

不过采用匿名内部类的方式有很多缺点,比如参数只能接受对象,即使你关心的只是行为;不够简洁,样板代码太多;代码难读,没有清楚表达程序员的意图。

Java8新增了方法引用及lambda来简化行为参数化的实现。上面的功能使用方法引用或lambda实现可能是这样的:

 public static List<Apple> filterApple(List<Apple> apples, ApplePredicate p) {
       List<Apple> result = new ArrayList<Apple>();
       for (Apple apple : apples) {
           if (p.test(apple)) {
               result.add(apple);
           }
       }
       return result;
   }

   public static void main(String[] args) {
       List<Apple> apples = Arrays
               .asList(new Apple("Green"), new Apple("Red"));
       // lambda
       filterApple(apples, (apple) -> {
           return "Green".equals(apple.getColor());
       });
       // 方法引用
       filterApple(apples, Apple::isGreen);
   }

使用Lambda或方法引用,代码不仅更简洁,意图表现的也更明显。

下篇我们将详细讲解lambda及方法引用。

以上是关于函数式编程与Lambda表达式(上)的主要内容,如果未能解决你的问题,请参考以下文章

Java函数式编程和lambda表达式

Java函数式编程和lambda表达式

函数式编程

Java8函数式编程

Java8函数式编程

Java8函数式编程