自己理解Java中的lambda

lambda是什么

“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。

将一个变量传入一个匿名函数然后对传入函数进行操作。由于java中并没有脱离类而存在的函数,所以通常独立函数是以一个匿名内部类+一个方法构成的。lambda表达式代替的函数既没有方法名也没有访问修饰符、明确的返回类型声明。

实现解析

下面将解析下lambda与java的逻辑。

函数式变换最大的特点是:将一个函数(方法)赋值给一个变量。

函数式编程环境中比如javaScript

var fun = function(){
  ...
}

那么在Java中大概是这个样子的。

var doSomthing = public void doSomthing(){
  ...
}

这个public 关键字是多余的,代码就变成了这个样子。

var doSomthing = void doSomthing(){
  ...
}

这个返回值类型可以依据内部return类型推导,所以返回值类型也不须要的。

var doSomthing = doSomthing(){
  ...
}

方法名在之前已经定义过了,代码就变成了这个样子。

var doSomthing = (){
  ...
}

由于这样看起来怪怪的。所以使用->来定义方法参数和主体。()表示方法的参数列表,{}内部表示方法体。单行方法体可以省略{},强烈不建议这么做。

var doSomthing = ()->{
  ...
}

这就相当于一个代码块被赋值给了一个变量,这就是一个lambda表达式。

var这个关键字1.8版本的java中是没有的。那么这个变量是什么呢。

在java1.8中所有的 lambda表达式本身就是某个接口的实现,所以var应该是某个接口。
下面定义一个接口

public interface MethodInterface {
    void doSomething();
}

一个接口函数需要被实现的接口类型,我们叫它”函数式接口“。为了避免后来的人在这个接口中增加接口函数导致其有多个接口函数需要被实现,变成"非函数接口”,我们可以在这个上面加上一个声明@FunctionalInterface, 这样别人就无法在里面添加新的接口函数了。

@FunctionalInterface
public interface MethodInterface {
    void doSomething();
}

函数式接口通常只有一个方法。

我们就可以直接把Lambda作为参数传给函数, 而传统的Java必须有明确的接口实现的定义。
那么上面的函数就成了

  MethodInterface methodInterface = ()->{
    ...
  }

那么我们将如何使用它呢.

  methodInterface.doSomthing();

这么调用即可。

这个接口通用性很强并且定义起来太麻烦,我们是不是有其他办法替换掉MethodInterface这个接口。

有的,在jdk1.8的java.util.function包中包含了大量定义好的接口。

接口名 参数 返回值
Consumer<T> T void
BiConsumer<T, U> T,U void
BiConsumer<T, U, R> T,U R
BooleanSupplier Boolean
DoubleBinaryOperator Double,Double Double

以上列举并不完全。
当然可以向上述文章那样自定义接口方法类型但是需要@FunctionalInterface注解

实战代码

创建线程接口方式
接口

package java.lang;

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

public class LambdaTest {

    private static final int TOTAL = 5000;


    private static AtomicInteger i = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        Executor executor = Executors.newCachedThreadPool();
        CountDownLatch countDownLatch = new CountDownLatch(TOTAL);

        for(int j=0;j<TOTAL;j++){

            executor.execute(()->{
                    add();
                    countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        System.out.println("求和的结果为:"+i);

    }

    private static void add(){
        i.incrementAndGet();
    }

}

总结

  1. 一个代码块被赋值给了一个变量。
  2. lambda表达式本身就是某个接口的实现。
posted @ 2018-04-20 14:39  枫飘雪落  阅读(1973)  评论(0编辑  收藏  举报