文章

函数式编程-闭包、柯里化

闭包(Closure)

何为闭包,闭包就是函数对象外界变量绑定在一起,形成的整体。例如

public class ClosureTest1 {
    interface Lambda {
        int add(int y);
    }
    
    public static void main(String[] args) {
        int x = 10;

        highOrder(y -> x + y);
    }

    static void highOrder(Lambda lambda) {
        System.out.println(lambda.add(20));
    }
}
  • 代码中的 y \rightarrow x + yx = 10,就形成了一个闭包
  • 可以想象成,函数对象有个背包,背包里可以装变量随身携带,将来函数对象甭管传递到多远的地方,包里总装着个 x = 10
  • 有个限制,局部变量 x 必须是 final 或 effective final 的,effective final 意思就是,虽然没有用 final 修饰,但就像是用 final 修饰了一样,不能重新赋值,否则就语法错误。
    • 意味着闭包变量,在装进包里的那一刻,就不能变化了
    • 道理也简单,为了保证函数的不变性,防止破坏成道
  • 闭包是一种给函数执行提供数据的手段,函数执行既可以使用函数入参,还可以使用闭包变量

public class ClosureTest2 {

    //创建10个任务对象,每个对象单独编号
    @Test
    void function() {
        // 闭包作用:给函数对象提供参数以外的数据
        List<Runnable> collect = IntStream.range(0, 10).mapToObj(i -> {
            int no = i + 1;
            return (Runnable) () -> System.out.println(Thread.currentThread().getName() + "-任务编号-" + no);
        }).collect(Collectors.toList());

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        collect.forEach(executorService::execute);

        executorService.shutdown();
    }
}

柯里化(Carrying)

柯里化的作用是让函数对象分步执行(本质上是利用多个函数对象和闭包)

例如:

public class Carrying1Test {
    public static void main(String[] args) {
        highOrder(a -> b -> a + b);
    }

    static void highOrder(Step1 step1) {
        Step2 step2 = step1.exec(10);
        System.out.println(step2.exec(20));
        System.out.println(step2.exec(50));
    }

    interface Step1 {
        Step2 exec(int a);
    }

    interface Step2 {
        int exec(int b);
    }
}

代码中

  • a \rightarrow ... 是第一个函数对象,它的返回结果 b \rightarrow ... 是第二个函数对象
  • 后者与前面的参数 a 构成了闭包
  • step1.exec(10) 确定了 a 的值是 10
  • ,返回第二个函数对象 step2,a 被放入了 step2 对象的背包记下来了
  • step2.exec(20) 确定了 b 的值是 20,此时可以执行 a + b 的操作,得到结果 30
  • step2.exec(50) 分析过程类似

例:

    //把三份数据合在一起
    interface  Fa {
        Fb apply(List<Integer> a);
    }
    
    interface  Fb {
        Fc apply(List<Integer> a);
    }
    
    interface  Fc {
        List<Integer> apply(List<Integer> a);
    }
    
    Fb step1() {

        List<Integer> x = Arrays.asList(1, 2, 3);

        return  b -> c -> {
            ArrayList<Integer> list = new ArrayList<>();
            list.addAll(x);
            list.addAll(b);
            list.addAll(c);
            return list;
        };
    }

    Fc step2(Fb fb) {
        List<Integer> y = Arrays.asList(4, 5, 6);
        return fb.apply(y);

    }

    void step3(Fc fc) {
        List<Integer> z = Arrays.asList(7, 8, 9);
        List<Integer> apply = fc.apply(z);
        System.out.println(apply);
    }
    
    @Test
    void function1() {
        step3(step2(step1()));
    }
License:  CC BY 4.0