1.函数式编程概述

1.1为什么要学函数式编程

java8引入了函数式编程,在工作中应用得特别广泛,如果不学习可能会看不懂公司中同事的代码。

函数式编程对于海量数据的处理特别有帮助,提供了并行流,可以让程序员不用自己进行并发编程(这无疑是有难度的)。

代码可读性其实会更高,避免嵌套地狱,可以看看下面这个例子。

image-20220218204642572

image-20220218204704806

1.2 函数式编程思想

面向对象编程关注什么对象做什么事情,但是函数事编程把关注点转移到了数据:对数据做哪些处理。

优点有:

  • 代码简洁
  • 接近于自然语言,易于理解(看名字就大致知道在做什么操作)
  • 易于"并发编程"(使用并行流处理数据,比单线程处理更具有效率,不必自己并发编程,去解决头疼的数据安全问题)

2.Lambda表达式

jdk8的语法糖,主要是优化部分内部类的操作方法。它是函数式编程的一个重要体现——让我们不用关注是什么类,什么方法,而只需要关注对数据进行什么操作。

核心原则是可推导、可省略

例1:

匿名内部类创建线程。

 new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我是一只小小鸟...");
            }
        }).start();

使用Lambda简化下。

new Thread(() -> System.out.println("想要飞却怎么也飞不高...")).start();;

什么时候可以使用Lambda表达式呢?答案是匿名内部类的参数是一个接口,并且只有一个抽象方法需要被实现。这就是所谓的函数式接口。参考Runnable接口。@FunctionalInterface可以用来标注一个接口是函数式接口。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

我们到这里就可以领会开始说的函数式编程思想了:Lambda表达式不关注类名,不关注方法名,因此他们都可以省略。只关注是什么数据(参数),对数据做什么操作(方法体)。

下面来做一个练习。

例2:调用下面方法实现对a,b进行自定义运算。

  public static int calculateNum(IntBinaryOperator operator) {
        int a  = 10;
        int b = 20;
        return  operator.applyAsInt(a, b);
    }

参数IntBinaryOperatorjava的util包中自带的工具类,我们虽然不认识,但可以点进去看看,是个函数式接口。

@FunctionalInterface
public interface IntBinaryOperator {

    /**
     * Applies this operator to the given operands.
     *
     * @param left the first operand
     * @param right the second operand
     * @return the operator result
     */
    int applyAsInt(int left, int right);
}

实现就变得很简单了。

先做一个内部类的调用实现。

 int cal1  = calculateNum(
                new IntBinaryOperator() {
                    @Override
                    public int applyAsInt(int left, int right) {
                        return left + right;
                    }
                }
        );

再写一个Lambda实现。

   int cal2 = calculateNum((left,right)->{
            return left* right;
        });

再来体会下Lambda表达式所展示的函数式编程思想:我并不关心calculateNum中是哪个类作为参数,也不关心这个类中是哪个方法来帮我做操作,我只像关心,我要传几个参数,我对我的数据进行什么操作。这样我们就可以把那些无关必要的东西省略,让我们代码变得更加简洁。

而且,写一个Lambda表达式在idea中特别简单,只要一个匿名内部类可以被简化未Lambda表达式,我们都可以使用Alt+enter将它简化成Lambda表达式。而且一个Lambda表达式看不懂,也可以使用同样的方式转换为匿名内部类。